Skip to main content
Version: Old ArrowSquid docs

Substrate typegen

Since @subsquid/substrate-typegen@8.0.0

The substrate typegen tool is a part of Subsquid SDK. It generates TypeScript wrappers for interfacing Substrate events and calls.

Usage:

npx squid-substrate-typegen typegen.json

Within the substrate-based templates there is also an sqd shorthand command for executing this exact line:

sqd typegen

If necessary, multiple config files can be supplied:

npx squid-substrate-typegen typegen0.json typegen1.json ...

The structure of the typegen.json config file is best illustrated with an example:

{
"outDir": "src/types",
"specVersions": "https://v2.archive.subsquid.io/metadata/kusama",
"pallets": {
// add one such section for each pallet
"Balances": {
"events": [
// list of events to generate wrappers for
"Transfer"
],
"calls": [
// list of calls to generate wrappers for
"transfer_allow_death"
],
"storage": [
"Account"
],
"constants": [
"ExistentialDeposit"
]
}
}
}

The specVersions field is either

To generate all items defined by a given pallet, set any of the events, calls, storage or constants fields to true, e.g.

{
"outDir": "src/types",
"specVersions": "kusamaVersions.jsonl",
"pallets": {
"Balances": {
// generate wrappers for all Balances pallet constants
"constants": true
}
}
}

TypeScript wrappers

Wrappers generated by the typegen command can be found in the specified outDir (src/types by convention). Assuming that this folder is imported as types (e.g. with import * as types from './types'), you'll be able to find the wrappers at:

  • for events: types.events.${palletName}.${eventName}
  • for calls: types.calls.${palletName}.${callName}
  • for storage items: types.storage.${palletName}.${storageItemName}
  • for constants: types.constants.${palletName}.${constantName}

All identifiers (pallet name, call name etc) are lowerCamelCased. E.g. the constant Balances.ExistentialDeposit becomes types.events.balances.existentialDeposit and the call Balances.set_balance becomes types.calls.setBalance.

Examples

Events and calls

import {events, calls} from './types'

processor.run(new TypeormDatabase(), async ctx => {
for (let block of ctx.blocks) {
for (let event of block.events) {
if (event.name == events.balances.transfer.name) {
let rec: {from: Bytes, to: Bytes, amount: bigint}
if (events.balances.transfer.v1020.is(event)) {
let [from, to, amount, fee] =
events.balances.transfer.v1020.decode(event)
rec = {from, to, amount}
}
// ... decode all runtime versions similarly
// with events.balances.transfer.${ver}.is/.decode
}
}
for (let call of block.calls) {
if (call.name == calls.balances.forceTransfer.name) {
let rec: {source: Bytes, dest: Bytes, value: bigint} | undefined
if (calls.balances.forceTransfer.v1020.is(call)) {
let res =
calls.balances.forceTransfer.v1020.decode(call)
assert(res.source.__kind === 'AccountId')
assert(res.dest.__kind === 'AccountId')
rec = {
source: res.source.value,
dest: res.dest.value,
value: res.value
}
}
// ... decode all runtime versions similarly
// with calls.balances.forceTransfer.${ver}.is/.decode
}
}
})

Storage

See Storage queries.

Constants

import {constants} from './types'
// ...
processor.run(new TypeormDatabase(), async ctx => {
for (let block of ctx.blocks) {
if (constants.balances.existentialDeposit.v1020.is(block.header)) {
let c = new constants.balances.existentialDeposit.v1020.get(block.header)
ctx.log.info(`Balances.ExistentialDeposit (runtime version V1020): ${c}`)
}
}
})