Skip to content

Examples

Nikhil Ranjan edited this page Sep 22, 2022 · 9 revisions

Here you will find a list of examples that takes you through the basics of connecting to a node, retrieving data from the Node and chain and execute transactions on the chain. It uses the ApiPromise interface.

Prerequisites

For the following examples, you need a local node. Compile astar-collator at https://github.com/AstarNetwork/astar. It is usually convenient testing with local dev node:

target/release/astar-collator --dev

Development accounts

Some of the examples use the following accounts:

  • Alice
  • Bob

Those accounts are easy to add if you don't have/see them. The seed of Alice's account is //Alice (via keyring.addUri(...), dev seed implied) and the seed of Bob is... well you guess...

Listen to new blocks

This example shows how to subscribe to new blocks.

It displays the block number every time a new block is seen by the node you are connected to.

NOTE: The example runs until you stop it with CTRL+C

// Import the API
import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

async function main () {
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // We only display a couple, then unsubscribe
  let count = 0;

  // Subscribe to the new headers on-chain. The callback is fired when new headers
  // are found, the call itself returns a promise with a subscription that can be
  // used to unsubscribe from the newHead subscription
  const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
    console.log(`Chain is at block: #${header.number}`);

    if (++count === 256) {
      unsubscribe();
      process.exit(0);
    }
  });
}

main().catch(console.error);

Listen to balance changes

This example shows how to instantiate astar.js and use it to connect to a node and retrieve balance updates.

// Import the API
import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

// Known account we want to use (available on dev chain, with funds)
const Alice = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';

async function main () {
  // Create an await for the API
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // Retrieve the initial balance. Since the call has no callback, it is simply a promise
  // that resolves to the current on-chain value
  let { data: { free: previousFree }, nonce: previousNonce } = await api.query.system.account(Alice);

  console.log(`${Alice} has a balance of ${previousFree}, nonce ${previousNonce}`);
  console.log(`You may leave this example running and start example 06 or transfer any value to ${Alice}`);

  // Here we subscribe to any balance changes and update the on-screen value
  api.query.system.account(Alice, ({ data: { free: currentFree }, nonce: currentNonce }) => {
    // Calculate the delta
    const change = currentFree.sub(previousFree);

    // Only display positive value changes (Since we are pulling `previous` above already,
    // the initial balance change will also be zero)
    if (!change.isZero()) {
      console.log(`New balance change of ${change}, nonce ${currentNonce}`);

      previousFree = currentFree;
      previousNonce = currentNonce;
    }
  });
}

main().catch(console.error);

Unsubscribe from listening to updates

This example shows how to subscribe to and later unsubscribe from listening to block updates.

In this example we're calling the built-in unsubscribe() function after a timeOut of 20s to cleanup and unsubscribe from listening to updates.

// Import the API
import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

async function main () {
  // Create a new instance of the api
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // Subscribe to chain updates and log the current block number on update.
  const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
    console.log(`Chain is at block: #${header.number}`);
  });

  // In this example we're calling the unsubscribe() function that is being
  // returned by the api call function after 20s.
  setTimeout(() => {
    unsubscribe();
    console.log('Unsubscribed');
  }, 20000);
}

main().catch(console.error);

Read storage

Many important variables are available through the storage API. This example shows how to call a few of those APIs.

// Import the API
import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

// Our address for Alice on the dev chain
const ALICE = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';

async function main () {
  // Create a new instance of the api
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // Make our basic chain state/storage queries, all in one go
  const [{ nonce: accountNonce }, now, validators] = await Promise.all([
    api.query.system.account(ALICE),
    api.query.timestamp.now(),
    api.query.session.validators()
  ]);

  console.log(`accountNonce(${ALICE}) ${accountNonce}`);
  console.log(`last block timestamp ${now.toNumber()}`);

  if (validators && validators.length > 0) {
    // Retrieve the balances for all validators
    const validatorBalances = await Promise.all(
      validators.map((authorityId) =>
        api.query.system.account(authorityId)
      )
    );

    // Print out the authorityIds and balances of all validators
    console.log('validators', validators.map((authorityId, index) => ({
      address: authorityId.toString(),
      balance: validatorBalances[index].data.free.toHuman(),
      nonce: validatorBalances[index].nonce.toHuman()
    })));
  }
}

main().catch(console.error).finally(() => process.exit());

Read storage, at a specific blockhash

In addition to querying the latest storage, you can make storage queries at a specific blockhash. Be aware that the node applies a pruning strategy and typically only keeps the last 256 blocks, unless run in archive mode.

import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

// Our address for Alice on the dev chain
const ALICE = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const BOB = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty';

async function main () {
  // Create a new instance of the api
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // Retrieve the last block header, extracting the hash and parentHash
  const { hash, parentHash } = await api.rpc.chain.getHeader();

  console.log(`last header hash ${hash.toHex()}`);

  // Retrieve the balance at the preceding block for Alice using an at api
  const apiAt = await api.at(parentHash);
  const balance = await apiAt.query.system.account(ALICE);

  console.log(`Alice's balance at ${parentHash.toHex()} was ${balance.data.free}`);

  // Now perform a multi query, returning multiple balances at once
  const balances = await api.query.system.account.multi([ALICE, BOB]);

  console.log(`Current balances for Alice and Bob are ${balances[0].data.free} and ${balances[1].data.free}`);
}

main().catch(console.error).finally(() => process.exit());

Make a simple transfer

This sample shows how to create a transaction to make a transfer from one account to another.

// Import the API
import { ApiPromise } from '@polkadot/api';
import { WsProvider } from '@polkadot/rpc-provider';
import { options } from '@astar-network/astar-api';

// Import Keyring for accounts
import { Keyring } from '@polkadot/keyring';

const BOB = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty';

async function main () {
  // Create a new instance of the api
  const provider = new WsProvider('ws://localhost:9944');
  const api = new ApiPromise(options({ provider }));
  await api.isReady;

  // Construct the keyring after the API (crypto has an async init)
  const keyring = new Keyring({ type: 'sr25519' });

  // Add Alice to our keyring with a hard-derivation path (empty phrase, so uses dev)
  const alice = keyring.addFromUri('//Alice');

  // Create a extrinsic, transferring 12345 units to Bob
  const transfer = api.tx.balances.transfer(BOB, 12345);

  // Sign and send the transaction using our account
  const hash = await transfer.signAndSend(alice);

  console.log('Transfer sent with hash', hash.toHex());
}

main().catch(console.error).finally(() => process.exit());