Introduction

What we will do here is to write a query to list all the transaction for a given Polkadot address as seen in the screenshot below.

Pre-requisites

Have gone through the SubQuery Hello World exercise. This ensures your environment has all the required applications.

Step 1: Run subql init

This will set up the scaffolding making everything a lot easier.

~/Code/subQuery/projects$ subql init
Project name [subql-starter]: subql-list-transactions
Git repository: 
RPC endpoint [wss://polkadot.api.onfinality.io/public-ws]: 
Authors: sa
Description: 
Version: [1.0.0]: 
License: [Apache-2.0]: 
Init the starter package... subql-list-transactions is ready
~/Code/subQuery/projects$ 

Step 2: Create a schema

The first step is to create your schema file which “defines the shape of your data”. Here we will define 2 entities or objects, Account and Transfer.

type Account @entity {
  id: ID!
  sentTransfers: [Transfer] @derivedFrom(field: "from")
  receivedTransfers: [Transfer] @derivedFrom(field: "to")
}

type Transfer @entity {
  id: ID!
  amount: BigInt
  to: Account!
  from: Account!
}

Step 3: Update the manifest file

In the manifest file, we want to create a handler called handleTransfer (to be written next). This is a standard substrate/Eventhandler and we will filter on the balances module. The filter is optional but recommended as they significantly reduce the amount of data processed by your SubQuery project and will improve indexing performance.

specVersion: 0.0.1
description: ""
repository: ""
schema: ./schema.graphql
network:
  endpoint: wss://polkadot.api.onfinality.io/public-ws
dataSources:
  - name: main
    kind: substrate/Runtime
    startBlock: 6716560
    mapping:
      handlers:
        - handler: handleTransfer
          kind: substrate/EventHandler
          filter:
            module: balances
            method: Transfer

Step 4: Writing the mappings

This is perhaps the most challenging part for those still learning SubQuery and Polkdadot. What the code below does is create a helper function called “ensureAccounts” and a handleTransfer EventHandler function to grab the transferred amount along with the to and from Id.

import {SubstrateExtrinsic,SubstrateEvent,SubstrateBlock} from "@subql/types";
import {Transfer, Account} from "../types";
import {Balance} from "@polkadot/types/interfaces";

async function ensureAccounts(accountIds: string[]): Promise<void> {
    for (const accountId of accountIds) {
        const account = await Account.get(accountId);
        if (!account) {
            await new Account(accountId).save();
        }
    }
}

export async function handleTransfer(event: SubstrateEvent): Promise<void> {
    const {
        event: {
            data: [from, to, amount],
        },
    } = event;
    await ensureAccounts([from.toString(), to.toString()]);
    const transferInfo = new Transfer(
        `${event.block.block.header.number.toNumber()}-${event.idx}`,
    );
    transferInfo.fromId = from.toString();
    transferInfo.toId = to.toString();
    transferInfo.amount = (amount as Balance).toBigInt();
    await transferInfo.save();
}

Step 5: Build and deploy

Run the standard commands.

yarn codegen
yarn build
docker-compose pull & docker-compose up

Step 6: Query

Now comes the fun part, the query. Below is an example query that can be used.

query {
    accounts (first:15 orderBy:CREATED_AT_DESC filter:{id: {equalTo: "12qvDzHzs3LFBnir7UAYR154t4ZWNLjMehniqLhTp2CBCeW4"}} ) {
        nodes {
            id
            createdAt
            updatedAt
          recievedTransfers {
            edges {
              node {
                id
                amount
              }
            }
          }
        }
    }
    transfers ( orderBy:CREATED_AT_DESC filter:{id: {equalTo: "12qvDzHzs3LFBnir7UAYR154t4ZWNLjMehniqLhTp2CBCeW4"}} ) {
        nodes {
            id
          createdAt
          updatedAt
            amount
            toId
            fromId
        }
    }
}

This will return:

{
  "data": {
    "accounts": {
      "nodes": [
        {
          "id": "12qvDzHzs3LFBnir7UAYR154t4ZWNLjMehniqLhTp2CBCeW4",
          "createdAt": "2021-09-07T00:01:15.719+00:00",
          "updatedAt": "2021-09-07T00:01:15.719+00:00",
          "recievedTransfers": {
            "edges": [
              {
                "node": {
                  "id": "6716562-3",
                  "amount": "20000000000"
                }
              },
              {
                "node": {
                  "id": "6716591-1",
                  "amount": "700000000000"
                }
              }
            ]
          }
        }
      ]
    },
    "transfers": {
      "nodes": []
    }
  }
}

And this matches subscan.

Leave a Reply

Your email address will not be published. Required fields are marked *