Sign and Broadcast Transaction

To complete any bonding or withdrawal operation on Polkadot, sign the unsigned transaction provided by the Staking API and broadcast it to the network.

1. Prepare the transaction

Retrieve an unsigned serialized transaction from the relevant API endpoint, e.g., staking/bond,staking/nominate, staking/withdraw-unbonded.

2. Sign the transaction

Sign the transaction using the following code:

import { readFileSync } from "fs";
import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";
import '@polkadot/api-augment';

async function sign () {
  // Polkadot websocket url
  const provider = process.env.PROVIDER;
  // sr25519 secret key filename
  const secretFileName = process.env.SECRET_FILE_NAME;
  // password of secret key
  const password = process.env.PASSWORD;
  // transaction in base64
  const rawTransaction = process.env.RAW_TRANSACTION;

  // connect to polkadot node
  const wsProvider = new WsProvider(provider);
  const api = await ApiPromise.create({ provider: wsProvider });
  await api.isReady;

  // load keyring file
  const keyring = new Keyring({ type: "sr25519" });
  const fileContent = readFileSync(
    secretFileName,
    "utf8"
  );
  const keyInfo = JSON.parse(fileContent);
  const sender = keyring.addFromJson(keyInfo);
  // decode secret key
  sender.decodePkcs8(password);

  const unsigned = api.tx(rawTransaction);

  // sign transaction
  const signedExtrinsic = await unsigned.signAsync(sender);
  console.log('signedExtrinsic', signedExtrinsic.toHuman());

  // print signed transaction
  const hexEx = signedExtrinsic.toHex()
  console.log('signedExtrinsic toHex', hexEx);

  await api.disconnect()
}

// run sign function
sign().catch((error) => {
  console.error(error);
  process.exit(1);
});

Upon successful execution, the script prints the signed transaction, ready for broadcasting.

3. Send the transaction

Broadcast the transaction to the Polkadot network by sending a POST request to /api/v1/polkadot/{network}/tx/send.

Example request (for westend network):

curl --request POST \
     --url https://api.p2p.org/api/v1/polkadot/westend/tx/send \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <token>' \
     --header 'content-type: application/json' \
     --data '
     {
       "signedTransaction": "0x450284002c6eca5cdaa3e87d7f8e06d10015bf0508b52d301c8991af113d5cf49a53553f01befdb7fa39c5a995a8d58676a0513d082be"
     }'
  • signedTransactionsigned transaction in hex format.

Example response:

{
  "result": {
    "status": "success",
    "blockHash": "0x0628743b05ffb4c9d5ea2144b359af38910f0ae439a685f57d85b50b9481ba3f",
    "blockId": "17168395",
    "extrinsicId": "0xb838911d5a5f965f33b8ee134e1115b5b9902abfc567f0c3050073faf9d3c3e0",
    "transactionHash": "0x450284002c6eca5cdaa3e87d7f8e06d10015bf0508b52d301c8991af113d5cf49a53553f01befdb7fa39c5a995a8d58676a0513d082be",
    "signerAccount": "5H6ryBWChC5w7eaQ4GZjo329sEnhvjetSr6MBEt42mZ5tPw5",
    "createdAt": "2023-08-15T15:07:54.795Z"
  }
}
  • staus — transaction status.
  • blockHash — block hash in which the transaction was included.
  • blockId — unique block identifier.
  • extrinsicId — unique extrinsic identifier.
  • transactionHash — signed transaction in hex format.
  • signerAccount — account that signed the transaction.
  • createdAt — timestamp of the transaction in the ISO 8601 format.

What's next?