This is the code to build a transaction to register a Stake Pool using cardano-serialization-lib
:
export const submitRegistrationTransaction = async (
mnemonic,
poolCertificate
) => {
//const privateKey = await getPrivateKeyFromEntropy(entropy);
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 stakeAddr = CardanoWasm.RewardAddress.new(
CardanoWasm.NetworkInfo.testnet().network_id(),
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(poolCertificate);
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);
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());
}
This is how you create the stake pool certificate:
export const createStakePoolCertificate = (
mnemonic,
stakePoolName,
relayIP,
relayPort,
pledge,
cost,
poolMarginNumerator,
poolMarginDenominator
) => {
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 stakeAddr = CardanoWasm.RewardAddress.new(
CardanoWasm.NetworkInfo.testnet().network_id(),
CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash())
)
const privateKey = deriveSpendPrivateKey(accountKey, 0).to_raw_key();
// Declare variables for pool params
const operatorKeyHash = utxoPubKey.to_raw_key().hash().to_bech32('ed25519_pk');
const nodeKeyGenKES = cardanocliJs.nodeKeyGenKES(stakePoolName);
const nodeKeyGen = cardanocliJs.nodeKeyGen(stakePoolName);
const nodeOperationalCert = cardanocliJs.nodeIssueOpCert(stakePoolName);
const vrfKeyAccount = cardanocliJs.nodeKeyGenVRF(stakePoolName);
//const kesKeyFile = readFileSync(nodeKeyGenKES.vkey, 'utf-8');
//console.log(CardanoWasm.KESSignature.from_bytes(Buffer.from(JSON.parse(kesKeyFile).cborHex), "hex"));
const vrfKeyFile = readFileSync(vrfKeyAccount.vkey, 'utf-8');
//const vrfKeyHash = CardanoWasm.VRFKeyHash.from_hex(JSON.parse(vrfKeyFile).cborHex.substring(4));
const vrfKeyHash = CardanoWasm.VRFKeyHash.from_bytes(fromHex(JSON.parse(vrfKeyFile).cborHex.substring(4)));
const poolMargin = CardanoWasm.UnitInterval.new(
CardanoWasm.BigNum.from_str(poolMarginNumerator), // numerator
CardanoWasm.BigNum.from_str(poolMarginDenominator) // denominator
);
const poolOwner = CardanoWasm.Ed25519KeyHashes.new();
poolOwner.add(CardanoWasm.Ed25519KeyHash.from_bech32(operatorKeyHash));
const relays = CardanoWasm.Relays.new();
const relay = CardanoWasm.Relay.new_single_host_addr(
CardanoWasm.SingleHostAddr.new(
relayPort,
CardanoWasm.Ipv4.new(new Uint8Array(relayIP.split('.').map((segment) => Number.parseInt(segment, 10))))
)
);
relays.add(relay);
// Prepare pool params
const poolParams = CardanoWasm.PoolParams.new(
CardanoWasm.Ed25519KeyHash.from_bech32(operatorKeyHash),
vrfKeyHash,
CardanoWasm.BigNum.from_str(pledge),
CardanoWasm.BigNum.from_str(cost),
poolMargin,
stakeAddr,
poolOwner,
relays
);
// Create Pool Registration
const poolRegistration = CardanoWasm.PoolRegistration.new(poolParams);
console.log(poolRegistration);
// Generate Pool Certificate
const poolCertificate = CardanoWasm.Certificate.new_pool_registration(poolRegistration)
return poolCertificate;
}