I'm having trouble retrieving the historic balances on Kusama. On Polkadot the exact same code works, so I'm not sure where the issue lies.

/* Kusama address, api init above */
const query_addr = "GyGN5AZe886p5mk6YMmXyksz683LYTLgzdzWRzTK29oLbru"

/* get the current free balance */
const { data: { free: free_now } } = await api.query.system.account(query_addr)
console.log(" now", free_now.toString())

/* init historic */
const block_hash = await api.rpc.chain.getBlockHash(1337)
const api_at = await api.at(block_hash)

/* get the historic balance */
const { data: { free: free_then } } = await api_at.query.system.account(query_addr)
console.log("then", free_then.toString())

/* get the difference */
console.log("diff", free_now.sub(free_then).toString())

The above code yields api_at.query.system.account is not a function. Additionally when I log Object.keys(api_at.system.account) I cannot see the account entry either, so I'm assuming at that point of the runtime it was stored elsewhere.

How can I make the above query work on older blocks?

  • FYI: Shawn has a tool that graphs historical balances: shawntabrizi.com/substrate-balance-graph
    – Squirrel
    Mar 26, 2022 at 7:51
  • That is nice for those who want a tool. Not quite for my specific usecase for my integration requirements (exactly at payouts), but certainly useful for a lookup. Mar 26, 2022 at 13:59

1 Answer 1


The short answer: use const free_then = api_at.query.balances.freeBalance(query_addr)

For the longer version... You are correct that Kusama went through a number of runtime upgrades and in the current iteration balances are stored as part of system.account. Right at launch however, things were a bit different.

The 3 parts currently stored inside system.account were stored in -

  • balances.freeBalance - as above, the free balance
  • balances.reservedBalance - the reserved balance
  • system.accountNonce - the actual account nonce

You will notice that when a transaction is sent in this older layout, 2 storage entries needs to be updated: the nonce and the balance. In the current iteration this turns into a single write, which is much more effective.

Balances could also be stored inside balances.account, which just contains the data entry as you are mapping it in your question, effectively combining the reserved and free entries.

If you wish to trawl the whole chain or just protect against where it may be at a specific block, I would suggest checking for the existence of the above queries before making them, something like

const free = apiAt.query.system.account
  ? (await apiAt.query.system.account(addr)).data.free
  : apiAt.query.balances.account
    ? (await apiAt.query.balances.account(addr)).free
    ? await apiAt.query.balances.freeBalance(addr)
  • I am back on track. Cheers! Mar 26, 2022 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.