Staking API Tutorial
An example on how to send a transaction using Blockdaemon's BNB Staking API.
On this page, you will find a TypeScript example showing how to send a BNB transaction using the BNB Staking API. It includes functions for staking, deactivating stakes, and restaking.
import RpcClient from '@binance-chain/javascript-sdk/lib/rpc';
import { types, Transaction, crypto } from '@binance-chain/javascript-sdk';
const apiAddress = 'https://svc.blockdaemon.com/boss';
const REQUEST_OPTIONS = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': process.env['BOSS_API_KEY'],
'X-Client-ID': process.env['X_CLIENT_ID'],
},
};
const PRIVATE_KEY = process.env['PRIVATE_KEY'] || '';
if (!PRIVATE_KEY) {
throw new Error('No private key found in environment');
}
const rpcClient = new RpcClient('https://data-seed-pre-0-s1.bnbchain.org', 'testnet');
async function signAndBroadcastDelegation(
client: RpcClient,
signBytes: string,
privateKey: string,
): Promise<any> {
const signMsg = hexToObject(signBytes);
const privKeyBuf = Buffer.from(privateKey, 'hex');
const signature = crypto.generateSignature(signBytes, privKeyBuf);
if (signMsg.msgs.length !== 1) {
throw new Error(`Invalid number of messages ${signMsg.msgs.length}`);
}
const delegateMsg = signMsg.msgs[0].value;
const msg = new types.BscDelegateMsg({
delegator_addr: delegateMsg.delegator_addr,
validator_addr: delegateMsg.validator_addr,
delegation: {
denom: delegateMsg.delegation.denom,
amount: parseInt(delegateMsg.delegation.amount),
},
side_chain_id: delegateMsg.side_chain_id,
});
return signAndBroadcastTx(client, signMsg, msg, privKeyBuf, signature);
}
async function signAndBroadcastUndelegation(
client: RpcClient,
signBytes: string,
privateKey: string,
): Promise<any> {
const signMsg = hexToObject(signBytes);
const privKeyBuf = Buffer.from(privateKey, 'hex');
const signature = crypto.generateSignature(signBytes, privKeyBuf);
if (signMsg.msgs.length !== 1) {
throw new Error(`Invalid number of messages ${signMsg.msgs.length}`);
}
const delegateMsg = signMsg.msgs[0].value;
const msg = new types.BscUndelegateMsg({
delegator_addr: delegateMsg.delegator_addr,
validator_addr: delegateMsg.validator_addr,
amount: {
denom: delegateMsg.amount.denom,
amount: parseInt(delegateMsg.amount.amount),
},
side_chain_id: delegateMsg.side_chain_id,
});
return signAndBroadcastTx(client, signMsg, msg, privKeyBuf, signature);
}
async function signAndBroadcastRedelegation(
client: RpcClient,
signBytes: string,
privateKey: string,
): Promise<any> {
const signMsg = hexToObject(signBytes);
const privKeyBuf = Buffer.from(privateKey, 'hex');
const signature = crypto.generateSignature(signBytes, privKeyBuf);
if (signMsg.msgs.length !== 1) {
throw new Error(`Invalid number of messages ${signMsg.msgs.length}`);
}
const delegateMsg = signMsg.msgs[0].value;
const msg = new types.BscReDelegateMsg({
delegator_addr: delegateMsg.delegator_addr,
validator_src_addr: delegateMsg.validator_src_addr,
validator_dst_addr: delegateMsg.validator_dst_addr,
amount: {
denom: delegateMsg.amount.denom,
amount: parseInt(delegateMsg.amount.amount),
},
side_chain_id: delegateMsg.side_chain_id,
});
return signAndBroadcastTx(client, signMsg, msg, privKeyBuf, signature);
}
async function signAndBroadcastTx(
client: RpcClient,
signMsg: any,
msg: types.BaseMsg,
privKeyBuf: Buffer,
signature: Buffer,
): Promise<any> {
const tx = new Transaction({
chainId: signMsg.chain_id,
msg: msg.getMsg(),
accountNumber: parseInt(signMsg.account_number),
sequence: parseInt(signMsg.sequence),
memo: '',
source: 0,
});
tx.addSignature(crypto.generatePubKey(privKeyBuf), signature);
return client.broadcastDelegate(tx);
}
function hexToObject(hexString: string) {
const buffer = Buffer.from(hexString, 'hex');
const jsonString = buffer.toString('utf-8');
return JSON.parse(jsonString);
}
async function createStake(privateKey: string, requestOptions: any) {
const request = {
amount: '100000000',
delegator_address: crypto.getAddressFromPrivateKey(
privateKey,
'bnb',
),
};
requestOptions.body = JSON.stringify(request);
const response = await fetch(`${apiAddress}/v1/binance/testnet/stake-intents`, requestOptions);
if (!response.ok) {
throw new Error('Response from BOSS API was not ok: ' + await response.text());
}
const responseJson = await response.json();
if (!responseJson.binance) {
throw new Error('Response from BOSS API did not include binance field: ' + JSON.stringify(responseJson));
}
const broadcastResult = await signAndBroadcastDelegation(
rpcClient,
responseJson.binance.unsigned_transaction,
privateKey,
);
if (broadcastResult.code !== 0) {
throw new Error('Broadcast failed: ' + JSON.stringify(broadcastResult));
}
console.log('Broadcast successful: ' + JSON.stringify(broadcastResult));
}
async function createDeactivateStake(privateKey: string, requestOptions: any) {
const request = {
amount: '100000000',
delegator_address: crypto.getAddressFromPrivateKey(
privateKey,
'bnb',
),
};
requestOptions.body = JSON.stringify(request);
const response = await fetch(`${apiAddress}/v1/binance/testnet/deactivation-intents`, requestOptions);
if (!response.ok) {
throw new Error('Response from BOSS API was not ok: ' + await response.text());
}
const responseJson = await response.json();
if (!responseJson.binance) {
throw new Error('Response from BOSS API did not include binance field: ' + JSON.stringify(responseJson));
}
const broadcastResult = await signAndBroadcastUndelegation(
rpcClient,
responseJson.binance.unsigned_transaction,
privateKey,
);
if (broadcastResult.code !== 0) {
throw new Error('Broadcast failed: ' + JSON.stringify(broadcastResult));
}
console.log('Broadcast successful: ' + JSON.stringify(broadcastResult));
}
async function createRestake(privateKey: string, requestOptions: any) {
const request = {
amount: '100000000',
delegator_address: crypto.getAddressFromPrivateKey(
privateKey,
'bnb',
),
old_validator_address: 'bva1pnww8kx30sz4xfcqvn8wjhrn796nf4dq77hcpa',
};
requestOptions.body = JSON.stringify(request);
const response = await fetch(`${apiAddress}/v1/binance/testnet/restake-intents`, requestOptions);
if (!response.ok) {
throw new Error('Response from BOSS API was not ok: ' + await response.text());
}
const responseJson = await response.json();
if (!responseJson.binance) {
throw new Error('Response from BOSS API did not include binance field: ' + JSON.stringify(responseJson));
}
const broadcastResult = await signAndBroadcastRedelegation(
rpcClient,
responseJson.binance.unsigned_transaction,
privateKey,
);
if (broadcastResult.code !== 0) {
throw new Error('Broadcast failed: ' + JSON.stringify(broadcastResult));
}
console.log('Broadcast successful: ' + JSON.stringify(broadcastResult));
}
createStake(PRIVATE_KEY, REQUEST_OPTIONS)
.then(() => process.exit(0))
.catch(err => {
console.error(err);
process.exit(1);
});
// createDeactivateStake(PRIVATE_KEY, REQUEST_OPTIONS)
// .then(() => process.exit(0))
// .catch(err => {
// console.error(err);
// process.exit(1);
// });
// createRestake(PRIVATE_KEY, REQUEST_OPTIONS)
// .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