Hi guys,
I would like to figure out why signing key is not being used.
I’m getting ‘“transaction submit error ShelleyTxValidationError ShelleyBasedEraAlonzo (ApplyTxError [UtxowFailure (WrappedShelleyEraFailure (MissingVKeyWitnessesUTXOW (WitHashes (fromList [KeyHash “d0cb4b4c7e82380f2867ddd2a88c377aa04c4c70d6b373cca280f03e”]))))])”’
I have wallet manager class:
import { mnemonicToEntropy } from 'bip39';
import * as CardanoWasm from "@emurgo/cardano-serialization-lib-nodejs"
const entropy = mnemonicToEntropy(
[ "fuel", "erode", "cotton", "pole", "unit", "grace", "forum", "shed", "solid", "corn", "nose", "play", "exit", "liquid", "case" ].join(' ')
);
export const getPrivateKey = () => {
const keyDetails = getKeyDetails();
return keyDetails.privateKey;
}
export const getPublicKey = () => {
const keyDetails = getKeyDetails();
return keyDetails.publicKey;
}
export const getBaseAddress = () => {
const keyDetails = getKeyDetails()
const baseAddr = CardanoWasm.BaseAddress.new(
CardanoWasm.NetworkInfo.testnet().network_id(),
CardanoWasm.StakeCredential.from_keyhash(keyDetails.utxoPubKey.to_raw_key().hash()),
CardanoWasm.StakeCredential.from_keyhash(keyDetails.stakeKey.to_raw_key().hash()),
);
return baseAddr;
}
const getKeyDetails = () => {
const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
Buffer.from(entropy, 'hex'),
Buffer.from(''),
);
const privateKey = rootKey.to_raw_key();
const publicKey = rootKey.to_public().to_raw_key();
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();
return { privateKey, publicKey, utxoPubKey, stakeKey }
}
function harden(num: number): number {
return 0x80000000 + num;
}
and the code for sending funds from my wallet to some 3rd party address
import * as WASM_lib from "@emurgo/cardano-serialization-lib-nodejs"
import { fromHex, toHex } from "./helloworld";
import * as walletManager from "./walletManager"
import * as fs from "fs"
import fetch from "node-fetch";
const DESTINATION_ADDRESS = () =>
WASM_lib.Address.from_bech32(
"addr_test1wpwkkr2sh346h45lx852ffv8l64we0kkahdxe6l5zl70vnc9przaf"
);
export async function lockFunds() {
const fee = 600000;
const amountToTransfer = 2000000; //2ADA
const ownerAddress = walletManager.getBaseAddress().to_address().to_bech32();
console.log(`owner address: ${ownerAddress}`);
console.log(`hash ${walletManager.getPublicKey().hash()}`);
console.log(`priv key bech32 ${walletManager.getPrivateKey().to_bech32()}`);
const input = WASM_lib.TransactionInput.new(
WASM_lib.TransactionHash.from_bytes(fromHex("364b50a7eda80f7a7dcca3d31c2bb13da25edf54e97374a8a6d0febeb8a11fb7")), 0
);
var output = WASM_lib.TransactionOutput.new(
DESTINATION_ADDRESS(),
WASM_lib.Value.new(WASM_lib.BigNum.from_str(amountToTransfer.toString()))
)
var outputOwner = WASM_lib.TransactionOutput.new(
walletManager.getBaseAddress().to_address(),
WASM_lib.Value.new(WASM_lib.BigNum.from_str((1000000000 - amountToTransfer - fee).toString()))
)
const transactionWitnessSet = WASM_lib.TransactionWitnessSet.new();
const transactionInputs = WASM_lib.TransactionInputs.new();
transactionInputs.add(input);
const transactionOutputs = WASM_lib.TransactionOutputs.new();
transactionOutputs.add(output);
transactionOutputs.add(outputOwner);
const requiredSigners = WASM_lib.Ed25519KeyHashes.new();
requiredSigners.add(walletManager.getPublicKey().hash());
const txBody = WASM_lib.TransactionBody.new(
transactionInputs,
transactionOutputs,
WASM_lib.BigNum.from_str(fee.toString())
);
txBody.set_required_signers(requiredSigners);
const transaction = WASM_lib.Transaction.new(
WASM_lib.TransactionBody.from_bytes(txBody.to_bytes()),
WASM_lib.TransactionWitnessSet.from_bytes(
transactionWitnessSet.to_bytes()
)
);
const serializedTx = toHex(transaction.to_bytes());
const txVkeyWitnesses = await signTx(serializedTx);
transactionWitnessSet.set_vkeys(txVkeyWitnesses.vkeys() as WASM_lib.Vkeywitnesses);
const signedTx = WASM_lib.Transaction.new(
WASM_lib.TransactionBody.from_bytes(txBody.to_bytes()),
WASM_lib.TransactionWitnessSet.from_bytes(
transactionWitnessSet.to_bytes()
)
);
var transactionInBytes = signedTx.to_bytes();
console.log("Full Tx Size", transactionInBytes.length);
await fs.promises.writeFile('c:/s/cardano-nft-minter/tokens/AdamNFT/tx_body.bin', transactionInBytes);
let result = await submitTx(toHex(transactionInBytes));
console.log("tx submitted", result);
}
const signTx = async (
tx,
) => {
const rawTx = WASM_lib.Transaction.from_bytes(Buffer.from(tx, 'hex'));
const txWitnessSet = WASM_lib.TransactionWitnessSet.new();
const vkeyWitnesses = WASM_lib.Vkeywitnesses.new();
const txHash = WASM_lib.hash_transaction(rawTx.body());
const vkey = WASM_lib.make_vkey_witness(txHash, walletManager.getPrivateKey());
vkeyWitnesses.add(vkey);
txWitnessSet.set_vkeys(vkeyWitnesses);
return txWitnessSet;
};
const submitTx = async (tx) => {
const result = await blockfrostRequest(
`/tx/submit`,
{ 'Content-Type': 'application/cbor' },
Buffer.from(tx, 'hex')
);
return result;
};
const blockfrostRequest = async (endpoint, headers = null, body = null) => {
return await fetch('https://cardano-testnet.blockfrost.io/api/v0' + endpoint, {
headers: {
project_id: "some_project_id",
...headers,
"User-Agent": "some-marketplace",
},
method: body ? "POST" : "GET",
body,
}).then((res) => res.json())
.catch(r => {
console.log(r);
})
}