Staking API Tutorial

An example showing how to send a Cosmos transaction using the Blockdaemon Staking API.

Here is a TypeScript example showing how to send a Cosmos transaction using the Staking API.

import { fromBase64, toBase64 } from '@cosmjs/encoding';
import { SignDoc, TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
import { isDeliverTxSuccess, StargateClient } from '@cosmjs/stargate';
import { HttpEndpoint, Tendermint34Client } from '@cosmjs/tendermint-rpc';
​
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
​
async function getAddress(wallet: DirectSecp256k1HdWallet): Promise<string> {
  const acc = await wallet.getAccounts();
  if (acc.length < 1) throw 'Not enough account in the wallet';
  if (!acc[0]) throw 'Invalid account in the wallet';
  return acc[0].address;
}
​
export async function broadcastTx(
  client: StargateClient,
  bytes: Uint8Array,
): Promise<boolean> {
  try {
    const broadcastResponse = await client.broadcastTx(bytes);
    return broadcastResponse && isDeliverTxSuccess(broadcastResponse);
  } catch (err) {
    console.error(err);
  }
  return false;
}
​
async function signAndCommit(
  cosmos: StargateClient,
  wallet: DirectSecp256k1HdWallet,
  tx: string,
) {
  if (!tx) throw 'Transaction is undefined';
  const signDoc = SignDoc.decode(fromBase64(tx));
​
  const { signature, signed } = await wallet.signDirect(
    await getAddress(wallet),
    signDoc,
  );
​
  const txRaw = TxRaw.fromPartial({
    bodyBytes: signed.bodyBytes,
    authInfoBytes: signed.authInfoBytes,
    signatures: [fromBase64(signature.signature)],
  });
​
  const txRawBytes = TxRaw.encode(txRaw).finish();
  await broadcastTx(cosmos, txRawBytes);
}
​
async function createStake() {
  // get environment variables
  const { wallet_mnemonic, bossApiKey, clientId, rpcEndpoint } =
    getCosmosVariables();
​
  const wallet = await DirectSecp256k1HdWallet.fromMnemonic(wallet_mnemonic);
​
  const delegator_address = await getAddress(wallet);
  console.log(`Delegator address is: ${delegator_address}`);
​
  // create a stake intent with the Staking Reporting API
  const response = await createStakeIntent(bossApiKey, clientId, {
    delegator_address: delegator_address,
    amount: '10000000',
  });
  if (!response.cosmos) {
    throw 'Missing property `cosmos` in BOSS responce';
  }
​
  // get the unsigned transaction data returned by the Staking Reporting API
  const unsigned_transaction = response.cosmos.unsigned_transaction;
​
  const cosmosClient = await StargateClient.connect(rpcEndpoint);
  await signAndCommit(cosmosClient, wallet, unsigned_transaction);
}
​
async function deativateStake() {
  // get environment variables
  const { wallet_mnemonic, bossApiKey, clientId, rpcEndpoint } =
    getCosmosVariables();
​
  const wallet = await DirectSecp256k1HdWallet.fromMnemonic(wallet_mnemonic);
​
  const delegator_address = await getAddress(wallet);
  console.log(`Delegator address is: ${delegator_address}`);
​
  // create a stake intent with the Staking Reporting API
  const response = await createDeactivateionIntent(bossApiKey, clientId, {
    delegator_address: delegator_address,
    amount: '1000000',
  });
  if (!response.cosmos) {
    throw 'Missing property `cosmos` in BOSS responce';
  }
​
  // get the unsigned transaction data returned by the Staking Reporting API
  const unsigned_transaction = response.cosmos.unsigned_transaction;
  const cosmosClient = await StargateClient.connect(rpcEndpoint);
  await signAndCommit(cosmosClient, wallet, unsigned_transaction);
}
​
async function rewardsWithdrawal() {
  // get environment variables
  const { wallet_mnemonic, bossApiKey, clientId, rpcEndpoint } =
    getCosmosVariables();
​
  const wallet = await DirectSecp256k1HdWallet.fromMnemonic(wallet_mnemonic);
​
  const delegator_address = await getAddress(wallet);
  console.log(`Delegator address is: ${delegator_address}`);
​
  // create a stake intent with the Staking Reporting API
  const response = await createRewardsWithdrawalIntent(bossApiKey, clientId, {
    delegator_address: delegator_address,
  });
​
  if (!response.cosmos) {
    throw 'Missing property `cosmos` in BOSS responce';
  }
​
  // get the unsigned transaction data returned by the Staking Reporting API
  const unsigned_transaction = response.cosmos.unsigned_transaction;
​
  const cosmosClient = await StargateClient.connect(rpcEndpoint);
  await signAndCommit(cosmosClient, wallet, unsigned_transaction);
}
​
// a function for getting environment variables
function getCosmosVariables() {
  // check for the BOSS API key
  if (!process.env['BOSS_API_KEY']) {
    throw new Error('Please set the BOSS_API_KEY env variable.');
  }
​
  // check for the cosmos wallet mnemonic
  if (!process.env['WALLET_MNEMONIC']) {
    throw new Error(
      'Please set the WALLET_MNEMONIC env variable. It should be base58 encoded',
    );
  }
​
  // check for the Staking Reporting client id
  if (!process.env['CLIENT_ID']) {
    throw new Error('Please set the CLIENT_ID env variable');
  }
​
  // check for the Coscmos rpc endpoint
  if (!process.env['COSMO_RPC_ENDPOINT']) {
    throw new Error('Please set the CLIENT_ID env variable');
  }
  return {
    wallet_mnemonic: process.env['WALLET_MNEMONIC'],
    bossApiKey: process.env['BOSS_API_KEY'],
    clientId: process.env['CLIENT_ID'],
    rpcEndpoint: process.env['COSMO_RPC_ENDPOINT'],
  };
}
​
export type StakeIntentCosmosRequest = {
  delegator_address: string;
  amount: string;
};
​
export type DeactivationIntentCosmosRequest = {
  delegator_address: string;
  amount: string;
};
​
export type RewardsWithdrawalIntentCosmosRequest = {
  delegator_address: string;
};
​
export type StakeIntentCosmos = {
  base_address: string;
  pool_id: string;
  unsigned_transaction: string;
};
​
export type DeactivationIntentResponce = {
  deactivate_intent_id: string;
  protocol: string;
  network: string;
  cosmos?: StakeIntentCosmos;
  customer_id?: string;
};
​
export type RewardsWithdrawalIntentResponce = {
  protocol: string;
  network: string;
  cosmos?: StakeIntentCosmos;
  customer_id?: string;
};
​
export type StakeIntentResponce = {
  stake_intent_id: string;
  protocol: string;
  network: string;
  cosmos?: StakeIntentCosmos;
  customer_id?: string;
};
​
/* a function for creating a stake intent with the BOSS API */
function createStakeIntent(
  bossApiKey: string,
  clientId: string,
  request: StakeIntentCosmosRequest,
): Promise<StakeIntentResponce> {
  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
      'X-Client-ID': clientId,
    },
    body: JSON.stringify(request),
  };
​
  const network = 'testnet';
  // return the response from POST Create a New Stake Intent
  return fetch(
    `${process.env['BOSS_API_ADDRESS']}/v1/cosmos/${network}/stake-intents`,
    requestOptions,
  ).then(async (response: any) => {
    if (response.status != 200) {
      throw await response.json();
    }
    return response.json() as Promise<StakeIntentResponce>;
  });
}
​
function createDeactivateionIntent(
  bossApiKey: string,
  clientId: string,
  request: DeactivationIntentCosmosRequest,
): Promise<StakeIntentResponce> {
  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
      'X-Client-ID': clientId,
    },
    body: JSON.stringify(request),
  };
​
  const network = 'testnet';
  // return the response from POST Create a New Stake Intent
  return fetch(
    `${process.env['BOSS_API_ADDRESS']}/v1/cosmos/${network}/deactivation-intents`,
    requestOptions,
  ).then(async (response: any) => {
    if (response.status != 200) {
      throw await response.json();
    }
    return response.json() as Promise<StakeIntentResponce>;
  });
}
​
function createRewardsWithdrawalIntent(
  bossApiKey: string,
  clientId: string,
  request: RewardsWithdrawalIntentCosmosRequest,
): Promise<StakeIntentResponce> {
  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
      'X-Client-ID': clientId,
    },
    body: JSON.stringify(request),
  };
​
  const network = 'testnet';
  // return the response from POST Create a New Stake Intent
  return fetch(
    `${process.env['BOSS_API_ADDRESS']}/v1/cosmos/${network}/rewards/withdrawal-intents`,
    requestOptions,
  ).then(async (response: any) => {
    if (response.status != 200) {
      throw await response.json();
    }
    return response.json() as Promise<StakeIntentResponce>;
  });
}
​
// run the example
// createStake()
//   .then(() => process.exit(0))
//   .catch(err => {
//     console.error(err);
//     process.exit(1);
//   });
​
// deativateStake()
//   .then(() => process.exit(0))
//   .catch(err => {
//     console.error(err);
//     process.exit(1);
//   });
​
rewardsWithdrawal()
  .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.