<p>The error message &quot;MissingVKeyWitnessesUTXOW&quot; means you need to sign with the right key.
For delegation transaction, you need to sign with both your stake.skey and payment.skey.</p>

CC BY-SA 4.0
2022-03-02T17:46:34.703Z
It might be helpful to future readers if I clarify that contracts have types. You must specify that its a staking one or it will default to something else.
KryptoKing
CC BY-SA 4.0
2022-03-04T07:48:16.627Z
Hi @kawan, 
I am a little new to this isn't this exactly what i am doing here :

```` javascript
let spendCred = Cardano.StakeCredential.from_keyhash(spend.to_public().to_raw_key().hash());
            
let stakeCred = Cardano.StakeCredential.from_keyhash(stake.to_public().to_raw_key().hash());

 vkeyWitnesses.add(Cardano.make_vkey_witness(
                txHash,
                spend.to_raw_key(),
            ));

            vkeyWitnesses.add(Cardano.make_vkey_witness(
                 txHash,
                 stake.to_raw_key(),
            ));
````
Akshit vaid
CC BY-SA 4.0
2022-03-02T15:32:23.363Z
2022-03-02T15:32:23.363Z
Kawan
<p>This is the code I use to submit a staking transaction:</p>
<pre><code>export const createDelegationCertificate = (
  mnemonic
) =&gt; {

  const entropy = mnemonicToEntropy(mnemonic);

  const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
    Buffer.from(entropy, 'hex'),
    Buffer.from(''),
  );

  const accountKey = rootKey
    .derive(harden(1852)) // purpose
    .derive(harden(1815)) // coin type
    .derive(harden(0)); // account #0

  const utxoPubKey = accountKey
    .derive(0) // external
    .derive(0)
    .to_public();

  const stakeKey = accountKey
    .derive(2) // chimeric
    .derive(0)
    .to_public();

  const operatorKeyHash = utxoPubKey.to_raw_key().hash().to_bech32('ed25519_pk');
  const poolKeyHash = CardanoWasm.Ed25519KeyHash.from_bech32(operatorKeyHash);

  const stakeCredential = CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash());
  
  const stakeDelegation = CardanoWasm.StakeDelegation.new(stakeCredential, poolKeyHash);

  // Generate Stake Certificate
  const delegationCertificate = CardanoWasm.Certificate.new_stake_delegation(stakeDelegation)

  return delegationCertificate;

}
</code></pre>
<p>After that, create the transaction using the delegation certificate from the previous step:</p>
<pre><code>export const submitDelegationTransaction = async (
  mnemonic, 
  delegationCertificate
) =&gt; {

  const entropy = mnemonicToEntropy(mnemonic);

  const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
    Buffer.from(entropy, 'hex'),
    Buffer.from(''),
  );
  
  const accountKey = rootKey
    .derive(harden(1852)) // purpose
    .derive(harden(1815)) // coin type
    .derive(harden(0)); // account #0

  const utxoPubKey = accountKey
    .derive(0) // external
    .derive(0)
    .to_public();

  const stakeKey = accountKey
    .derive(2) // chimeric
    .derive(0)
    .to_public();

  const baseAddr = CardanoWasm.BaseAddress.new(
    CardanoWasm.NetworkInfo.testnet().network_id(),
    CardanoWasm.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
    CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
  );

  const privateKey = deriveSpendPrivateKey(accountKey, 0).to_raw_key();
  const stakingPrivateKey = deriveStakePrivateKey(accountKey, 0).to_raw_key();
  const fromAddress = baseAddr.to_address().to_bech32(&quot;addr_test&quot;);

  const params = await getParameters();

  const linearFee = CardanoWasm.LinearFee.new(
    CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.minFeeA.toString()),
    CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.minFeeB.toString())
  );
  
  const txBuilderConfig = CardanoWasm.TransactionBuilderConfigBuilder.new()
    .fee_algo(linearFee)
    .pool_deposit(CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.poolDeposit.toString()))
    .key_deposit(CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.keyDeposit.toString()))
    .max_value_size(params.data.genesis.alonzo.maxValueSize)
    .max_tx_size(params.data.genesis.shelley.protocolParams.maxTxSize)
    .coins_per_utxo_word(CardanoWasm.BigNum.from_str(params.data.genesis.alonzo.lovelacePerUTxOWord.toString()))
    .build();

  // instantiate the tx builder with the Cardano protocol parameters - these may change later on
  const txBuilder = CardanoWasm.TransactionBuilder.new(txBuilderConfig);

  const unspentOutputs = await getTxUnspentOutputs(fromAddress);
   
  // pointer address
  const shelleyChangeAddress = CardanoWasm.Address.from_bech32(fromAddress);

  // set the time to live - the absolute slot value before the tx becomes invalid
  const slot = await getSlotNo();
  txBuilder.set_ttl(slot.data.cardano.tip.slotNo + 10000);

  const certificates = CardanoWasm.Certificates.new();
  certificates.add(delegationCertificate);
  txBuilder.set_certs(certificates);

  // add a keyhash input - for ADA held in a Shelley-era normal address (Base, Enterprise, Pointer)
  txBuilder.add_inputs_from(unspentOutputs, 2); // LargestFirstMultiAsset

  // calculate the min fee required and send any change to an address
  txBuilder.add_change_if_needed(shelleyChangeAddress)

  // once the transaction is ready, we build it to get the tx body without witnesses
  const txBody = txBuilder.build()
  const txHash = CardanoWasm.hash_transaction(txBody);
  const witnesses = CardanoWasm.TransactionWitnessSet.new();
  const vkeyWitnesses = CardanoWasm.Vkeywitnesses.new();
  const vkeyWitness1 = CardanoWasm.make_vkey_witness(txHash, privateKey);
  const vkeyWitness2 = CardanoWasm.make_vkey_witness(txHash, stakingPrivateKey);

  vkeyWitnesses.add(vkeyWitness1);
  vkeyWitnesses.add(vkeyWitness2);

  witnesses.set_vkeys(vkeyWitnesses);
  witnesses.set_native_scripts(CardanoWasm.NativeScripts.new());
  
  // create the finalized transaction with witnesses
  const transaction = CardanoWasm.Transaction.new(
    txBody,
    witnesses,
    undefined, // transaction metadata
  );

  return toHexString(transaction.to_bytes());

}
</code></pre>

CC BY-SA 4.0
2023-03-28T10:20:07.903Z
2023-03-28T10:20:07.903Z
Falcon Stakepool
<p>i am trying to create a staking transaction using cardano serialisation library and then use blockfrost/infinito to send the transaction.
I am using @emurgo/cardano-serialization-lib-nodejs: ^9.1.4,</p>
<p>Here's my code :</p>
<pre><code>    createStakeTx(inputs, ttl, poolID, isFirstStake) {
        try {
            // let rootKey = Cardano.Bip32PrivateKey.from_bytes(Buffer.from(this.masterKey, 'hex'));
            console.log(
                'inside create stake tx ::::::::::::::'
            )
            console.log('inputs :', inputs); 
            console.log('ttl :', ttl);
            console.log('poolId :', poolID);
            console.log('isFirstStake :', isFirstStake);

            // this.masterKey = Cardano.Bip32PrivateKey.from_bip39_entropy(Buffer.from(entropy, 'hex'), Buffer.from(''))
            let rootKey = this.masterKey 
            let spend = rootKey
                .derive(harden(1852))
                .derive(harden(1815))
                .derive(harden(0))
                .derive(this.accountKey) // 1
                .derive(this.addressKey); // 34
            let spendPubKey = spend.to_public();

            let stake = rootKey
                .derive(harden(1852))
                .derive(harden(1815))
                .derive(harden(0))
                .derive(2)
                .derive(0);
            let stakePubkey = stake.to_public();
            let ed = stake.to_public().to_raw_key().hash();
            // console.log('ed :', ed);
            let spendCred = Cardano.StakeCredential.from_keyhash(spend.to_public().to_raw_key().hash());
            let stakeCred = Cardano.StakeCredential.from_keyhash(stake.to_public().to_raw_key().hash());

            // testnet: 0, mainnet: 1
            let address = Cardano.BaseAddress.new(1, spendCred, stakeCred).to_address().to_bech32();

            let linearFee = Cardano.LinearFee.new(
                Cardano.BigNum.from_str('44'),
                Cardano.BigNum.from_str('155381')
            );
            let txBuilder = Cardano.TransactionBuilder.new(
                linearFee,
                Cardano.BigNum.from_str('1000000'),
                Cardano.BigNum.from_str('500000000'),
                Cardano.BigNum.from_str('2000000'),
                16384,
                5000,
            );

            let sumInputs = bigNumber(0);
            inputs.forEach(element =&gt; {
                txBuilder.add_key_input(
                    spendPubKey.to_raw_key().hash(),
                    Cardano.TransactionInput.new(
                        Cardano.TransactionHash.from_bytes(Buffer.from(element.tx_id, 'hex')),
                        element.vout
                    ),
                    Cardano.Value.new(Cardano.BigNum.from_str(element.amount))
                );
                sumInputs = sumInputs.plus(element.amount);
            });

            txBuilder.set_ttl(ttl + 2000);

            let poolKeyHash = Cardano.Ed25519KeyHash.from_bytes(Buffer.from(poolID, 'hex'));
            let certs = Cardano.Certificates.new();

            if (isFirstStake == true) {
                certs.add(
                    Cardano.Certificate.new_stake_registration(
                        Cardano.StakeRegistration.new(
                            stakeCred
                        )
                    )
                );                
            }

            certs.add(
                Cardano.Certificate.new_stake_delegation(
                    Cardano.StakeDelegation.new(
                        stakeCred,
                        poolKeyHash
                    )
                )
            );

            txBuilder.set_certs(certs);

            let estimate = this.estimateStakeTxFee(inputs, poolID, isFirstStake);
            txBuilder.set_fee(Cardano.BigNum.from_str(bigNumber(estimate.fee).toFixed()));

            let changeAmount = bigNumber(0);
            console.log('sumInputs :', sumInputs)
            if (isFirstStake == true) {
                changeAmount = sumInputs.minus(KEY_DEPOSIT).minus(estimate.fee);
            } else {
                changeAmount = sumInputs.minus(estimate.fee);
            }

            console.log('changeAmount :', changeAmount)
            txBuilder.add_output(
                Cardano.TransactionOutput.new(
                    Cardano.Address.from_bech32(address),
                    Cardano.Value.new(Cardano.BigNum.from_str(changeAmount.toFixed()))
                )
            );

            let txBody = txBuilder.build();

            const txHash = Cardano.hash_transaction(txBody);

            let witnesses = Cardano.TransactionWitnessSet.new();
            let vkeyWitnesses = Cardano.Vkeywitnesses.new();
            vkeyWitnesses.add(Cardano.make_vkey_witness(
                txHash,
                spend.to_raw_key(),
            ));

            vkeyWitnesses.add(Cardano.make_vkey_witness(
                 txHash,
                 stake.to_raw_key(),
            ));

            witnesses.set_vkeys(vkeyWitnesses);

            let tx = Cardano.Transaction.new(
                txBody,
                witnesses,
            );
            console.log('rawtx ::', Buffer.from(tx.to_bytes()).toString('hex'))
            const res = await client.txSubmit(Buffer.from(tx.to_bytes()).toString('hex'));
            return res;
        } catch (err) {
            console.log('err: ', err);
            return null;
        }
    }    
</code></pre>
<p>// Error when i use blockfrost :</p>
<p>transaction submit error ShelleyTxValidationError ShelleyBasedEraAlonzo (ApplyTxError [UtxowFailure (WrappedShelleyEraFailure (MissingVKeyWitnessesUTXOW (WitHashes (fromList [KeyHash &quot;some hash&quot;])))),DelegsFailure (DelplFailure (DelegFailure (StakeDelegationImpossibleDELEG (KeyHashObj (KeyHash &quot;somehash&quot;)))))])</p>
<p>//Error when i use infinito :
{&quot;type&quot;:&quot;jsonwsp/fault&quot;,&quot;version&quot;:&quot;1.0&quot;,&quot;servicename&quot;:&quot;ogmios&quot;,&quot;fault&quot;:{&quot;code&quot;:&quot;client&quot;,&quot;string&quot;:&quot;Invalid request: DeserialiseFailure 539 &quot;Size mismatch when decoding \nRecord RecD.\nExpected 4, but found 3.&quot;.&quot;},&quot;reflection&quot;:{&quot;requestId&quot;:&quot;XEpib&quot;}} is an unknown result</p>
<p>Maybe i am just creating the transaction in a wrong way or my keys might be messed up.</p>
<p>Open to any help and suggestions</p>
<p>Thanks</p>

<staking><cardano-serialization-lib><blockfrost>
What am i doing wrong while creating this staking transaction?
# What am i doing wrong while creating this staking transaction?

(Asked by: username_0 on 2022-03-02)

i am trying to create a staking transaction using cardano serialisation library and then use blockfrost/infinito to send the transaction.
I am using @emurgo/cardano-serialization-lib-nodejs: ^9.1.4,
Here's my code :
    createStakeTx(inputs, ttl, poolID, isFirstStake) {
        try {
            // let rootKey = Cardano.Bip32PrivateKey.from_bytes(Buffer.from(this.masterKey, 'hex'));
            console.log(
                'inside create stake tx ::::::::::::::'
            )
            console.log('inputs :', inputs); 
            console.log('ttl :', ttl);
            console.log('poolId :', poolID);
            console.log('isFirstStake :', isFirstStake);

            // this.masterKey = Cardano.Bip32PrivateKey.from_bip39_entropy(Buffer.from(entropy, 'hex'), Buffer.from(''))
            let rootKey = this.masterKey 
            let spend = rootKey
                .derive(harden(1852))
                .derive(harden(1815))
                .derive(harden(0))
                .derive(this.accountKey) // 1
                .derive(this.addressKey); // 34
            let spendPubKey = spend.to_public();

            let stake = rootKey
                .derive(harden(1852))
                .derive(harden(1815))
                .derive(harden(0))
                .derive(2)
                .derive(0);
            let stakePubkey = stake.to_public();
            let ed = stake.to_public().to_raw_key().hash();
            // console.log('ed :', ed);
            let spendCred = Cardano.StakeCredential.from_keyhash(spend.to_public().to_raw_key().hash());
            let stakeCred = Cardano.StakeCredential.from_keyhash(stake.to_public().to_raw_key().hash());

            // testnet: 0, mainnet: 1
            let address = Cardano.BaseAddress.new(1, spendCred, stakeCred).to_address().to_bech32();

            let linearFee = Cardano.LinearFee.new(
                Cardano.BigNum.from_str('44'),
                Cardano.BigNum.from_str('155381')
            );
            let txBuilder = Cardano.TransactionBuilder.new(
                linearFee,
                Cardano.BigNum.from_str('1000000'),
                Cardano.BigNum.from_str('500000000'),
                Cardano.BigNum.from_str('2000000'),
                16384,
                5000,
            );

            let sumInputs = bigNumber(0);
            inputs.forEach(element => {
                txBuilder.add_key_input(
                    spendPubKey.to_raw_key().hash(),
                    Cardano.TransactionInput.new(
                        Cardano.TransactionHash.from_bytes(Buffer.from(element.tx_id, 'hex')),
                        element.vout
                    ),
                    Cardano.Value.new(Cardano.BigNum.from_str(element.amount))
                );
                sumInputs = sumInputs.plus(element.amount);
            });

            txBuilder.set_ttl(ttl + 2000);

            let poolKeyHash = Cardano.Ed25519KeyHash.from_bytes(Buffer.from(poolID, 'hex'));
            let certs = Cardano.Certificates.new();

            if (isFirstStake == true) {
                certs.add(
                    Cardano.Certificate.new_stake_registration(
                        Cardano.StakeRegistration.new(
                            stakeCred
                        )
                    )
                );                
            }

            certs.add(
                Cardano.Certificate.new_stake_delegation(
                    Cardano.StakeDelegation.new(
                        stakeCred,
                        poolKeyHash
                    )
                )
            );

            txBuilder.set_certs(certs);

            let estimate = this.estimateStakeTxFee(inputs, poolID, isFirstStake);
            txBuilder.set_fee(Cardano.BigNum.from_str(bigNumber(estimate.fee).toFixed()));

            let changeAmount = bigNumber(0);
            console.log('sumInputs :', sumInputs)
            if (isFirstStake == true) {
                changeAmount = sumInputs.minus(KEY_DEPOSIT).minus(estimate.fee);
            } else {
                changeAmount = sumInputs.minus(estimate.fee);
            }

            console.log('changeAmount :', changeAmount)
            txBuilder.add_output(
                Cardano.TransactionOutput.new(
                    Cardano.Address.from_bech32(address),
                    Cardano.Value.new(Cardano.BigNum.from_str(changeAmount.toFixed()))
                )
            );

            let txBody = txBuilder.build();

            const txHash = Cardano.hash_transaction(txBody);

            let witnesses = Cardano.TransactionWitnessSet.new();
            let vkeyWitnesses = Cardano.Vkeywitnesses.new();
            vkeyWitnesses.add(Cardano.make_vkey_witness(
                txHash,
                spend.to_raw_key(),
            ));

            vkeyWitnesses.add(Cardano.make_vkey_witness(
                 txHash,
                 stake.to_raw_key(),
            ));

            witnesses.set_vkeys(vkeyWitnesses);

            let tx = Cardano.Transaction.new(
                txBody,
                witnesses,
            );
            console.log('rawtx ::', Buffer.from(tx.to_bytes()).toString('hex'))
            const res = await client.txSubmit(Buffer.from(tx.to_bytes()).toString('hex'));
            return res;
        } catch (err) {
            console.log('err: ', err);
            return null;
        }
    }    

// Error when i use blockfrost :
transaction submit error ShelleyTxValidationError ShelleyBasedEraAlonzo (ApplyTxError [UtxowFailure (WrappedShelleyEraFailure (MissingVKeyWitnessesUTXOW (WitHashes (fromList [KeyHash "some hash"])))),DelegsFailure (DelplFailure (DelegFailure (StakeDelegationImpossibleDELEG (KeyHashObj (KeyHash "somehash")))))])
//Error when i use infinito :
{"type":"jsonwsp/fault","version":"1.0","servicename":"ogmios","fault":{"code":"client","string":"Invalid request: DeserialiseFailure 539 "Size mismatch when decoding \nRecord RecD.\nExpected 4, but found 3."."},"reflection":{"requestId":"XEpib"}} is an unknown result
Maybe i am just creating the transaction in a wrong way or my keys might be messed up.
Open to any help and suggestions
Thanks

**Tags:** staking, cardano-serialization-lib, blockfrost

---

## 2 answers

### Answer by username_1 on 2022-03-02. Score: 1

The error message "MissingVKeyWitnessesUTXOW" means you need to sign with the right key.
For delegation transaction, you need to sign with both your stake.skey and payment.skey.

> **Comments:**
> **username_2**: It might be helpful to future readers if I clarify that contracts have types. You must specify that its a staking one or it will default to something else.  
> **username_0**: Hi @kawan,  I am a little new to this isn't this exactly what i am doing here :  ```` javascript let spendCred = Cardano.StakeCredential.from_keyhash(spend.to_public().to_raw_key().hash());              let stakeCred = Cardano.StakeCredential.from_keyhash(stake.to_public().to_raw_key().hash());   vkeyWitnesses.add(Cardano.make_vkey_witness(                 txHash,                 spend.to_raw_key(),             ));              vkeyWitnesses.add(Cardano.make_vkey_witness(                  txHash,                  stake.to_raw_key(),             )); ````  

---

### Answer by username_3 on 2023-03-28. Score: 0

This is the code I use to submit a staking transaction:
export const createDelegationCertificate = (
  mnemonic
) => {

  const entropy = mnemonicToEntropy(mnemonic);

  const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
    Buffer.from(entropy, 'hex'),
    Buffer.from(''),
  );

  const accountKey = rootKey
    .derive(harden(1852)) // purpose
    .derive(harden(1815)) // coin type
    .derive(harden(0)); // account #0

  const utxoPubKey = accountKey
    .derive(0) // external
    .derive(0)
    .to_public();

  const stakeKey = accountKey
    .derive(2) // chimeric
    .derive(0)
    .to_public();

  const operatorKeyHash = utxoPubKey.to_raw_key().hash().to_bech32('ed25519_pk');
  const poolKeyHash = CardanoWasm.Ed25519KeyHash.from_bech32(operatorKeyHash);

  const stakeCredential = CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash());
  
  const stakeDelegation = CardanoWasm.StakeDelegation.new(stakeCredential, poolKeyHash);

  // Generate Stake Certificate
  const delegationCertificate = CardanoWasm.Certificate.new_stake_delegation(stakeDelegation)

  return delegationCertificate;

}

After that, create the transaction using the delegation certificate from the previous step:
export const submitDelegationTransaction = async (
  mnemonic, 
  delegationCertificate
) => {

  const entropy = mnemonicToEntropy(mnemonic);

  const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
    Buffer.from(entropy, 'hex'),
    Buffer.from(''),
  );
  
  const accountKey = rootKey
    .derive(harden(1852)) // purpose
    .derive(harden(1815)) // coin type
    .derive(harden(0)); // account #0

  const utxoPubKey = accountKey
    .derive(0) // external
    .derive(0)
    .to_public();

  const stakeKey = accountKey
    .derive(2) // chimeric
    .derive(0)
    .to_public();

  const baseAddr = CardanoWasm.BaseAddress.new(
    CardanoWasm.NetworkInfo.testnet().network_id(),
    CardanoWasm.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
    CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
  );

  const privateKey = deriveSpendPrivateKey(accountKey, 0).to_raw_key();
  const stakingPrivateKey = deriveStakePrivateKey(accountKey, 0).to_raw_key();
  const fromAddress = baseAddr.to_address().to_bech32("addr_test");

  const params = await getParameters();

  const linearFee = CardanoWasm.LinearFee.new(
    CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.minFeeA.toString()),
    CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.minFeeB.toString())
  );
  
  const txBuilderConfig = CardanoWasm.TransactionBuilderConfigBuilder.new()
    .fee_algo(linearFee)
    .pool_deposit(CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.poolDeposit.toString()))
    .key_deposit(CardanoWasm.BigNum.from_str(params.data.genesis.shelley.protocolParams.keyDeposit.toString()))
    .max_value_size(params.data.genesis.alonzo.maxValueSize)
    .max_tx_size(params.data.genesis.shelley.protocolParams.maxTxSize)
    .coins_per_utxo_word(CardanoWasm.BigNum.from_str(params.data.genesis.alonzo.lovelacePerUTxOWord.toString()))
    .build();

  // instantiate the tx builder with the Cardano protocol parameters - these may change later on
  const txBuilder = CardanoWasm.TransactionBuilder.new(txBuilderConfig);

  const unspentOutputs = await getTxUnspentOutputs(fromAddress);
   
  // pointer address
  const shelleyChangeAddress = CardanoWasm.Address.from_bech32(fromAddress);

  // set the time to live - the absolute slot value before the tx becomes invalid
  const slot = await getSlotNo();
  txBuilder.set_ttl(slot.data.cardano.tip.slotNo + 10000);

  const certificates = CardanoWasm.Certificates.new();
  certificates.add(delegationCertificate);
  txBuilder.set_certs(certificates);

  // add a keyhash input - for ADA held in a Shelley-era normal address (Base, Enterprise, Pointer)
  txBuilder.add_inputs_from(unspentOutputs, 2); // LargestFirstMultiAsset

  // calculate the min fee required and send any change to an address
  txBuilder.add_change_if_needed(shelleyChangeAddress)

  // once the transaction is ready, we build it to get the tx body without witnesses
  const txBody = txBuilder.build()
  const txHash = CardanoWasm.hash_transaction(txBody);
  const witnesses = CardanoWasm.TransactionWitnessSet.new();
  const vkeyWitnesses = CardanoWasm.Vkeywitnesses.new();
  const vkeyWitness1 = CardanoWasm.make_vkey_witness(txHash, privateKey);
  const vkeyWitness2 = CardanoWasm.make_vkey_witness(txHash, stakingPrivateKey);

  vkeyWitnesses.add(vkeyWitness1);
  vkeyWitnesses.add(vkeyWitness2);

  witnesses.set_vkeys(vkeyWitnesses);
  witnesses.set_native_scripts(CardanoWasm.NativeScripts.new());
  
  // create the finalized transaction with witnesses
  const transaction = CardanoWasm.Transaction.new(
    txBody,
    witnesses,
    undefined, // transaction metadata
  );

  return toHexString(transaction.to_bytes());

}


---

