> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Substrate typegen

> Generate type-safe wrappers for Substrate events, calls, storage, and ink! contracts.

`squid-substrate-typegen` generates TypeScript wrappers for interfacing Substrate events, calls,
storage items, and constants, aware of runtime version changes. A companion tool,
[`squid-ink-typegen`](#ink-contracts), does the same for [ink!](https://use.ink) smart contracts.
Install both with `--save-dev`.

## Generating wrappers

```bash theme={"system"}
npx squid-substrate-typegen typegen.json
```

If necessary, multiple config files can be supplied:

```bash theme={"system"}
npx squid-substrate-typegen typegen0.json typegen1.json ...
```

Paths in `typegen.json` are resolved relative to the config file. The structure is best
illustrated with an example:

```json theme={"system"}
{
  "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

* a metadata service endpoint URL, like
  ```
  https://v2.archive.subsquid.io/metadata/{network}
  ```
  or
* a path to a [`jsonl`](https://jsonlines.org) file generated by [`substrate-metadata-explorer(1)`](https://github.com/subsquid/squid-sdk/tree/master/substrate/substrate-metadata-explorer).

To generate all items defined by a given pallet, set any of the `events`, `calls`, `storage` or
`constants` fields to `true`. The `events`, `calls`, `storage`, and `constants` selectors can
also be set at the top level to select items across pallets, and a pallet entry can itself be
`true` to select the whole pallet.

<Info>
  In the rare cases when typegen needs pre-v14 type definitions, `typesBundle` accepts either a
  built-in chain name or a path to a JSON bundle (resolved relative to `typegen.json`):

  ```json theme={"system"}
  {
    "outDir": "src/types",
    "specVersions": "kusamaVersions.jsonl",
    "typesBundle": "kusama",
    ...
  }
  ```

  Built-in bundles include `acala`/`karura`, `aleph-node`, `altair`, `astar`, `basilisk`,
  `bifrost`, `calamari`, `clover`, `crust`, `darwinia`, `hydradx`, `khala`, `kilt`, `kintsugi`,
  `kusama`, `manta`, `moonbeam`/`moonbase`/`moonriver`, `parallel`/`heiko`, `pioneer`, `polkadot`,
  `reef`, `shell`, `shiden`, `shibuya`, `sora-substrate`, `statemint`/`statemine`, `subsocial`,
  `unique`/`quartz`, and `zeitgeist`. See also the
  [types bundle miniguide](../guides/substrate/types-bundle-miniguide).
</Info>

## 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.constants.balances.existentialDeposit` and the call
`Balances.set_balance` becomes `types.calls.balances.setBalance`.

Runtime constants are available directly from the wrappers:

```typescript theme={"system"}
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 = constants.balances.existentialDeposit.v1020.get(block.header)
      ctx.log.info(`Balances.ExistentialDeposit (runtime version V1020): ${c}`)
    }
  }
})
```

## Decoding events and calls

To decode events and calls, first determine the appropriate runtime version with `.is()`, then
decode them with `.decode()`:

```typescript theme={"system"}
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 queries

It is sometimes impossible to extract the required data with only event and call data without
querying the runtime state. The context exposes a lightweight JSON-RPC client at `ctx._chain.rpc`
with low-level methods for accessing the storage. However, the recommended way to query the
storage is with the type-safe wrappers exposed at `src/types/storage.ts`, following the
[general naming pattern](#typescript-wrappers):

```
storage.${palletName}.${storageName}
```

Note that the generated getters **always query historical blockchain state at the height derived
from their `block` argument**.

<Accordion title="Example of a generated storage wrapper">
  ```typescript title="src/types/balances/storage.ts" theme={"system"}
  import {sts, Block, Bytes, Option, Result, StorageType} from '../support'
  import * as v1050 from '../v1050'
  import * as v9420 from '../v9420'

  export const account = {
    v1050: new StorageType('Balances.Account', 'Default', [v1050.AccountId], v1050.AccountData) as AccountV1050,
    v9420: new StorageType('Balances.Account', 'Default', [v9420.AccountId32], v9420.AccountData) as AccountV9420,
  }

  export interface AccountV1050  {
    getDefault(block: Block): v1050.AccountData
    get(block: Block, key: v1050.AccountId): Promise<v1050.AccountData | undefined>
    getMany(block: Block, keys: v1050.AccountId[]): Promise<(v1050.AccountData | undefined)[]>
  }

  export interface AccountV9420  {
    getDefault(block: Block): v9420.AccountData
    get(block: Block, key: v9420.AccountId32): Promise<v9420.AccountData | undefined>
    getMany(block: Block, keys: v9420.AccountId32[]): Promise<(v9420.AccountData | undefined)[]>
    getKeys(block: Block): Promise<v9420.AccountId32[]>
    getKeys(block: Block, key: v9420.AccountId32): Promise<v9420.AccountId32[]>
    getKeysPaged(pageSize: number, block: Block): AsyncIterable<v9420.AccountId32[]>
    getKeysPaged(pageSize: number, block: Block, key: v9420.AccountId32): AsyncIterable<v9420.AccountId32[]>
    getPairs(block: Block): Promise<[k: v9420.AccountId32, v: v9420.AccountData | undefined][]>
    getPairs(block: Block, key: v9420.AccountId32): Promise<[k: v9420.AccountId32, v: v9420.AccountData | undefined][]>
    getPairsPaged(pageSize: number, block: Block): AsyncIterable<[k: v9420.AccountId32, v: v9420.AccountData | undefined][]>
    getPairsPaged(pageSize: number, block: Block, key: v9420.AccountId32): AsyncIterable<[k: v9420.AccountId32, v: v9420.AccountData | undefined][]>
  }
  ```
</Accordion>

The generated access interface provides methods for accessing:

* the default storage value with `getDefault(block)`
* a single storage value with `get(block, key)`
* multiple values in a batch call with `getMany(block, keys[])`
* all storage keys with `getKeys(block)`
* all keys with a given prefix with `getKeys(block, keyPrefix)` (only if the storage keys are decodable)
* paginated keys via `getKeysPaged(pageSize, block)` and `getKeysPaged(pageSize, block, keyPrefix)`
* key-value pairs via `getPairs(block)` and `getPairs(block, keyPrefix)`
* paginated key-value pairs via `getPairsPaged(pageSize, block)` and `getPairsPaged(pageSize, block, keyPrefix)`

```typescript title="src/main.ts" theme={"system"}
import {storage} from './types'

processor.run(new TypeormDatabase(), async ctx => {
  let aliceAddress = ss58.decode('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY').bytes
  for (const blockData of ctx.blocks) {
    if (storage.balances.account.v1050.is(blockData.header)) {
      let aliceBalance = (await storage.balances.account.v1050.get(blockData.header, aliceAddress))?.free
      ctx.log.info(`Alice free account balance at block ${blockData.header.height}: ${aliceBalance}`)
    }
  }
})
```

## ink! contracts

Use [`squid-ink-typegen`](https://github.com/subsquid/squid-sdk/tree/master/substrate/ink-typegen)
to generate facade classes for decoding ink! smart contract data from JSON ABI metadata:

```bash theme={"system"}
npx squid-ink-typegen --abi abi/erc20.json --output src/abi/erc20.ts
```

The generated source code exposes decoding methods, some useful types, and a class for performing
wrapped RPC queries, using `@subsquid/ink-abi` under the hood:

```typescript title="src/abi/erc20.ts" theme={"system"}
const _abi = new Abi(metadata)

export function decodeEvent(hex: string, topics: string[]): Event {
  return _abi.decodeEvent(hex, topics)
}

export function decodeMessage(hex: string): Message {
  return _abi.decodeMessage(hex)
}

export function decodeConstructor(hex: string): Constructor {
  return _abi.decodeConstructor(hex)
}
```

Usage in a batch handler:

```typescript theme={"system"}
processor.run(new TypeormDatabase(), async ctx => {
  for (let block of ctx.blocks) {
    for (let event of block.events) {
      if (event.name==='Contracts.ContractEmitted' &&
          event.args.contract===CONTRACT_ADDRESS) {

        let decoded = erc20.decodeEvent(event.args.data, event.args.topics)
        if (decoded.__kind==='Transfer') {
          // decoded is of type `Event_Transfer`
        }
      }
    }
  }
})
```

The generated `Contract` class provides facades for all state calls that don't mutate the
contract state (mutability is taken from the contract metadata):

```typescript theme={"system"}
// Generated code:
export class Contract {
    // optional blockHash indicates the block at which the state is queried
    constructor(private ctx: ChainContext, private address: string, private blockHash?: string) { }

    total_supply(): Promise<Balance> {
        return this.stateCall('0xdb6375a8', [])
    }

    balance_of(owner: Uint8Array): Promise<bigint> {
        return this.stateCall('0x6568382f', [owner])
    }
}
```

```typescript theme={"system"}
processor.run(new TypeormDatabase(), async ctx => {
  for (let block of ctx.blocks) {
    for (let event of block.events) {
       // query the balance at the current block
       const contract = new Contract(ctx, CONTRACT_ADDRESS, block.header.hash)
       let aliceAddress = ss58.decode('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY').bytes
       let aliceBalance = await contract.balance_of(aliceAddress)
    }
  }
})
```

For a complete worked example, see the [ink! contract indexing tutorial](../examples-tutorials/ink).
