Staking API Tutorial
How to send a transaction using Blockdaemon Cardano Staking API.
In this guide, you will find a TypeScript example showing how to send a Cardano transaction using the Cardano Staking API.
import * as CardanoWasm from '@emurgo/cardano-serialization-lib-nodejs';
import * as cbor from 'cbor';
const apiAddress = 'https://svc.blockdaemon.com/boss';
// Function to decode a hex-encoded transaction string into a TransactionBody object
function decodeTransaction(
transaction: string,
): CardanoWasm.TransactionBody {
return CardanoWasm.TransactionBody.from_bytes(
Buffer.from(transaction, 'hex'),
);
}
// Function to sign a transaction body with a list of keys, returning a full Transaction object
function signTransaction(
transactionBody: CardanoWasm.TransactionBody,
keys: CardanoWasm.PrivateKey[],
): CardanoWasm.Transaction {
const transactionHash = CardanoWasm.hash_transaction(transactionBody);
const witnesses = CardanoWasm.TransactionWitnessSet.new();
const vkeyWitnesses = CardanoWasm.Vkeywitnesses.new();
keys.forEach(key => {
vkeyWitnesses.add(CardanoWasm.make_vkey_witness(transactionHash, key));
});
witnesses.set_vkeys(vkeyWitnesses);
return CardanoWasm.Transaction.new(transactionBody, witnesses);
}
// Function to fetch Cardano variables from the environment
function getCardanoVariables() {
if (!process.env["BOSS_API_KEY"]) {
throw new Error('Please set the BOSS_API_KEY env variable.');
}
if (!process.env["PAYMENT_PRIVATE_KEY"]) {
throw new Error('Please set the PAYMENT_PRIVATE_KEY env variable. It should be base58 encoded');
}
if (!process.env["STAKE_PRIVATE_KEY"]) {
throw new Error('Please set the STAKE_PRIVATE_KEY env variable. It should be base58 encoded');
}
return {
paymentKey: CardanoWasm.PrivateKey.from_normal_bytes(cbor.decode( Buffer.from(process.env["PAYMENT_PRIVATE_KEY"],'hex'))),
stakeKey: CardanoWasm.PrivateKey.from_normal_bytes(cbor.decode( Buffer.from(process.env["STAKE_PRIVATE_KEY"],'hex'))),
bossApiKey: process.env["BOSS_API_KEY"],
};
}
// Helper function to create a base address
function getBaseAddress(paymentKey, stakeKey) {
return CardanoWasm.BaseAddress.new(
0, // network number 0 for preprod and 1 for mainnet
CardanoWasm.StakeCredential.from_keyhash(paymentKey.to_public().hash()),
CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_public().hash()),
);
}
// Helper function to handle common logic across transaction types
async function processTransaction(transactionType, requestOptions) {
const { paymentKey, stakeKey, bossApiKey } = getCardanoVariables();
const baseAddress = getBaseAddress(paymentKey, stakeKey);
const request = {
base_address: baseAddress.to_address().to_bech32(),
};
requestOptions.body = JSON.stringify(request);
const response = await fetch(`${apiAddress}/v1/cardano/preprod/${transactionType}`, requestOptions);
if (!response.ok) {
throw new Error('Response from BOSS API was not ok: ' + await response.text());
}
const responseJson = await response.json();
if (!responseJson.cardano) {
throw new Error('Response from BOSS API did not include cardano field: ' + JSON.stringify(responseJson));
}
const decodedTransaction = decodeTransaction(responseJson.cardano.unsigned_transaction);
const signedTransaction = signTransaction(decodedTransaction, [paymentKey, stakeKey]);
const signedTransactionHex = Buffer.from(signedTransaction.to_bytes()).toString('hex');
const submitResponse = await fetch(`${apiAddress}/v1/cardano/preprod/transaction-submission`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': bossApiKey
},
body: JSON.stringify({
signed_transaction: signedTransactionHex,
}),
});
if (!submitResponse.ok) {
throw new Error('Response from transaction submission was not ok: ' + await submitResponse.text());
}
return await submitResponse.json();
}
// Function to create a stake intent
async function createStake() {
return await processTransaction('stake-intents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': process.env["BOSS_API_KEY"],
},
});
}
// Function to create a deactivation intent
async function deactivateStake() {
return await processTransaction('deactivation-intents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': process.env["BOSS_API_KEY"]
},
});
}
// Function to create a rewards withdrawal intent
async function rewardsWithdrawal() {
return await processTransaction('rewards/withdrawal-intents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': process.env["BOSS_API_KEY"],
},
});
}
createStake()
.then(() => process.exit(0))
.catch(err => {
console.error(err);
process.exit(1);
});
👋 Need Help?
Contact us through email or our support page for any issues, bugs, or assistance you may need.
Updated about 1 month ago