I'm writing a client in Go that needs to scan balance transfers in Substrate chains - initially focused on Polkadot.

My current objective is to determine all balance transfers in a given block, and to record the sender & destination IDs along with the value transferred.

To simplify decoding & storage access I'm using Sidecar.

Balance Transfer Summary

If I understand correctly, balance transfers can be made by methods in the balances and utility pallets.

Balance transfer methods in balances pallet:

  • transfer
  • transferAll
  • transferKeepAlive

Balance transfer methods in utilities pallet:

  • batch
  • batchAll

Data Required

The data I need is the destination ID, sender ID and the value transferred.

In all cases, I am getting the sender ID directly from the Extrinsic signature.

For "standard" balance transfers that use balances.transfer, this data is present in the Extrinsic. Westend example here

This is not the case for balances.TransferAll - the Extrinsic does not directly hold data for value of the transfer - this must be obtained from the balances.Transfer event for that Extrinsic. Polkadot example here

For batched transactions under the utilities pallet, data for destination ID and value is obtained by looping over the Extrinsic.Arg.Calls and inspecting the Args of any balance transfer methods.

Current Approach

My app scans for Extrinsics that relate to balance transfers.

In the case of a utilities.batch or utilities.batchAll:

  • Get sender ID from Extrinsic
  • Loop over the Extrinsic Calls
  • Skip Calls whose methods do not relate to balance transfer (balances pallet, transfer, transferAll, transferKeepAlive methods)
  • Get destination ID and Value for balance transfer events from the call Args

In the case of balances.transfer, balances.transferAll or balances.transferKeepAlive Extrinsics:

  • Get sender ID from Extrinsic
  • Get destination ID from Extrinsic
  • Loop over Extrinsic Events
  • Skip those that are not: balances.Transfer, balances.TransferAll, balances.TransferKeepAlive
  • Get value from the data field of the Event

The data field of a balance transfer event as provided by Sidecar is an array of unlabeled strings. For example:

    "method": {
        "pallet": "balances",
        "method": "Transfer"
    "data": [

curl http://path-to-polkadot-mainnet-node-with-sidecar:8080/blocks/11555568 | jq '.extrinsics[3].events[3]'


  1. Is my understanding of balance transfers correct?
  2. Am I missing any potential balance transfer events?

Most importantly, can I rely on the third element in a balances transfer array provided by sidecar (as shown above) representing value?

It seems odd that this is not a named field, and it feels hacky accessing this data by means of an array index.



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy