Polkadot API Usage Example

View some examples showing how to use Blockdaemon Polkadot Staking API.

Polkadot API Usage Example

In this section, you will find TypeScript examples of how to send staking transactions using the Polkadot Staking API.

Broadcasting a transaction

The Blockdaemon Staking API returns unsigned transactions that the API user must sign and broadcast to the network to achieve the desired outcome. For Polkadot, this is usually done using the standardized Polkadot RPC endpoints and the Polkadot.js client.

import { ApiPromise, HttpProvider, WsProvider } from '@polkadot/api';
import type { KeyringPair } from '@polkadot/keyring/types';

// An example of signing and submitting a Polkadot transaction:
function signAndSubmitTx(
  api: ApiPromise,      // The Polkadot.js API client.
  account: KeyringPair, // The account you must sign this transaction with
  tx: string,           // The transaction itself.
): Promise<string> {
  const nonce = await api.rpc.system.accountNextIndex(account.address);

  return (await api.tx(tx).signAndSend(account, { nonce })).toHex();
}

// A convenient Polkadot connection error class.
export class PolkadotConnectionError extends Error {
  constructor(msg: string) {
    super('Can not connect to Polkadot: ' + msg);
  }
}

// A function that gets the URL of a Polkadot network node RPC
// and returns a Polkadot.js API object:
export async function connectToPolkadot(rpcUrl: string): Promise<ApiPromise> {
  try {
    const provider =
      rpcUrl.startsWith('ws://') || rpcUrl.startsWith('wss://')
        ? new WsProvider(rpcUrl)
        : rpcUrl.startsWith('http://') || rpcUrl.startsWith('https://')
        ? new HttpProvider(rpcUrl)
        : throwError(`Unsupported RPC URL: '${rpcUrl}'`);
    return await ApiPromise.create({ provider, throwOnConnect: true });
  } catch (err: any) {
    throw new PolkadotConnectionError(err.toString());
  }
}

const rpcUrl = "wss://example.com/Polkadot";

myAccount = (your account)

api = await connectToPolkadot(rpcUrl);

signAndSubmitTx(api, myAccount, myTx);

Creating a stake intent

Polkadot's delegation system allows for secure staking management without exposing your tokens. This can be done by using a Stash account or a Proxy.

The Stash account acts as a cold wallet. It holds your funds securely while the bound Blockdaemon Proxy account will nominate on its behalf. The Stash account retains full control over withdrawals and transfers and can replace the Proxy account as needed.

// Set here your Blockdaemon customer ID:
const customerID = "customer-1";

// Set here your Blockdaemon BOSS API key:
const bossApiKey = "1234567890abcdef";

// Set here the Polkadot network you want to stake on:
const polkadotNetwork = "westend";
// Use "mainnet" for real tokens and "westend" for testing tokens.

// Set here the Polkadot address (public key) of your proxy account:
const customerAddress = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y";

// Set here the HTTP address of the Blockdaemon public api:
const BossApiAddress = "https://svc.blockdaemon.com";

// A function to call Blockdaemon API to get back the data you need:
function createStakeIntent(
  bossApiKey: string,
  customerId: string,
  customerAddress: string,
): Promise {
  const callData = {
    customer_address: customerAddress, //Stash account or a proxy (staking or non-transfer)
  }

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
      'X-Client-ID': customerId,
    },
    body: JSON.stringify(callData),
  };

  // return the response from POST Create a New Stake Intent
  return fetch(
    `${BossApiAddress}/v1/polkadot/${polkadotNetwork}/stake-intents`,
    requestOptions,
  ).then(async response => {
    if (response.status != 200) {
      throw await response.json();
    }
    return response.json() as Promise
  })
}

// The structure of the BOSS API call response:
function stakeIntentResponseExample() {
  const stakeIntentResponse = await createStakeIntent(
    bossApiKey, customerID, customerAddress);

  // Your customer ID (the same that you submitted):
  const custID = stakeIntentResponse.customer_id;

  // The unique ID for the stake intent you just created:
  const stakeIntentId = stakeIntentResponse.stake_intent_id;

  // Should always be "polkadot":
  const protocol = stakeIntentResponse.protocol;

  // The network you submitted ("mainnet" or "westend"):
  const network = stakeIntentResponse.network;

  // The unique ID of your customer plan:
  const planId = stakeIntentResponse.plan_id;

  // Your proxy account address (the same that you submitted):
  const customerAddr = stakeIntentResponse.polkadot.customer_address;

  // The address of the proxy account you will nominate:
  const proxyAddress = stakeIntentResponse.polkadot.proxy_address;

  // An unsigned transaction that will do the nomination
  // when / if you sign and submit it (see the first example):
  const unsignedTransaction = stakeIntentResponse.polkadot.unsigned_transaction;
}

Deactivating a stake intent

When deactivating a staking intent, you can specify the DOT tokens to release:

  • Releasing all tokens will automatically revoke the nomination of our proxy account to stake for your customer account. If no amount is specified, all tokens will be released by default.
  • If you choose to release only a portion of your staked tokens, we will assume that you still want us to continue staking the remaining amount, and the nomination will not be revoked.

In both cases, the requested tokens will be marked for release from the staking bond, but the actual release will occur at the end of the staking period.

// Set here your Blockdaemon customer ID:
const customerID = "customer-1";

// Set here your Blockdaemon BOSS API key:
const bossApiKey = "1234567890abcdef";

// Set here the Polkadot network you want to stake on:
const polkadotNetwork = "westend";
// Use "mainnet" for real tokens and "westend" for testing tokens.

// Set here the Polkadot address (public key) of your proxy account:
const customerAddress = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y";

// Set here the amount of DOT tokens you want to free from the staking:
const dotAmount = "1000";

// Set here the HTTP address of the Blockdaemon public api:
const BossApiAddress = "https://svc.blockdaemon.com";

function createDeactivateIntent(
  bossApiKey: string,
  customerId: string,
  customerAddress: string,
  dotAmount: string,
): Promise {
  const callData = {
    customer_address: customerAddress, //Stash account or a proxy (staking or non-transfer)
    amount: dotAmount,
  }

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-API-Key': bossApiKey,
      'X-Client-ID': customerId,
    },
    body: JSON.stringify(callData),
  };

  // return the response from POST Create a New Deactivate Intent
  return fetch(
    `${BossApiAddress}/v1/polkadot/${polkadotNetwork}/deactivation-intents`,
    requestOptions,
  ).then(async response => {
    if (response.status != 200) {
      throw await response.json();
    }
    return response.json() as Promise
  })
}

// The structure of the BOSS API call response:
function deactivateIntentResponseExample() {
  const deactivateIntentResponse = await createDeactivateIntent(
    bossApiKey, customerID, customerAddress, dotAmount);

  // Your customer ID (the same that you submitted):
  const customerId = deactivateIntentResponse.customer_id;

  // The unique ID for the deactivate intent you just created:
  const stakeIntentId = deactivateIntentResponse.stake_intent_id;

  // Should always be "polkadot":
  const protocol = deactivateIntentResponse.protocol;

  // The network you submitted ("mainnet" or "westend"):
  const network = deactivateIntentResponse.network;

  // Your proxy account address (the same that you submitted):
  const customerAddr = deactivateIntentResponse.polkadot.customer_address;

  // The address of the proxy account you will nominate:
  const proxyAddress = deactivateIntentResponse.polkadot.proxy_address;

  // An unsigned transaction that will do the deactivation
  // when / if you sign and submit it (see the first example):
  const unsignedTransaction = deactivateIntentResponse.polkadot.unsigned_transaction;
}

Once signed and sent, the following transaction will mark the specified amount of tokens for freeing. If you choose to release all staked tokens, it will also revoke the nomination of our proxy account to stake for your customer account.

Withdrawing staked tokens

Once you deactivate a stake intent (partially or completely), the locked amount of DOT will no longer be held in staking. Instead, it will remain in your account's "staking" section. While they remain in this section, you can stake them again, but you cannot freely transfer them to another account.

To transfer these tokens to another account, you must "withdraw" them to your account's "free usage" section. Once you complete this action, you can spend or utilize them as desired.

// Set here your Blockdaemon customer ID:
const customerID = "customer-1";

// Set here your Blockdaemon BOSS API key:
const bossAPIKey = "1234567890abcdef";

// Set here the Polkadot network you want to stake on:
const polkadotNetwork = "westend";
// Use "mainnet" for real tokens and "westend" for testing tokens.

// Set here the Polkadot address (public key) of your proxy account:
const customerAddress = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y";

// Set here the HTTP address of the Blockdaemon public api:
const BossApiAddress = "https://svc.blockdaemon.com"
function createWithdrawIntent(
    bossAPIKey: string,
    customerId: string,
    customerAddress: string,
): Promise {
    const callData = {
        customer_address: customerAddress, //Stash account or a proxy (staking or non-transfer)
    }

    const requestOptions = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            'X-API-Key': bossAPIKey,
            'X-Client-ID': customerId,
        },
        body: JSON.stringify(callData),
    };

    // return the response from POST Create a New Deactivate Intent
    return fetch(
        `${BossApiAddress}/v1/polkadot/${polkadotNetwork}/withdrawal-intents`,
        requestOptions,
    ).then(async response => {
        if (response.status != 200) {
            throw await response.json();
        }
        return response.json() as Promise
    })
}

// The structure of the BOSS API call response:
function withdrawIntentResponseExample() {
    const withdrawIntentResponse = await createWithdrawIntent(
        bossAPIKey, customerID, customerAddress);

    // Your customer ID (the same that you submitted):
    const custID = withdrawIntentResponse.customer_id;

    // The unique ID for the withdraw intent you just created:
    const stakeIntentId = withdrawIntentResponse.stake_intent_id;

    // Should always be "polkadot":
    const protocol = withdrawIntentResponse.protocol;

    // The network you submitted ("mainnet" or "westend"):
    const network = withdrawIntentResponse.network;

    // Your proxy account address (the same that you submitted):
    const custAddr = withdrawIntentResponse.polkadot.customer_address;

    // An unsigned transaction that will do the withdrawal
    // when / if you sign and submit it (see the first example):
    const unsignedTransaction = withdrawIntentResponse.polkadot.unsigned_transaction;
}

When signed and broadcast, the transaction will release all deactivated tokens from staking.

👋 Need Help?

Contact us through email or our support page for any issues, bugs, or assistance you may need.