> ## 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.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.sqd.dev/feedback

```json
{
  "path": "/en/sdk/squid-sdk/resources/tools/typegen/state-queries",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Direct RPC queries

> Query chain state directly via wrapped RPC calls in Squid SDK — typegen-generated state-call wrappers for fetching contract storage and balances.

<Tabs>
  <Tab title="squid-evm-typegen">
    In order to make on-chain calls, one must set up a JSON-RPC endpoint using [setRpcEndpoint()](/en/sdk/squid-sdk/reference/processors/evm-batch/general#set-rpc-endpoint). We recommend using a private endpoint from e.g. [BlastAPI](https://blastapi.io/) or the SQD Cloud's [RPC addon](/en/cloud/resources/rpc-proxy), and set it via an environment variable:

    ```ts theme={"system"}
    //...
      .setRpcEndpoint(process.env.RPC_ETH_HTTP)
    //...
    ```

    You can define the `RPC_ETH_HTTP` in three ways:

    * for local runs, simply update the local `.env` file;
    * for squids deployed to Cloud define it as a [secret](/en/cloud/resources/env-variables) on your Cloud account;
    * if you are using the [RPC addon](/en/cloud/resources/rpc-proxy), leave it to the Cloud to define it for you.

    ## `Contract` class

    The EVM contract state is accessed using the `Contract` class generated by `squid-evm-typegen`. It takes a handler context and a contract address as constructor arguments. The state is always accessed at the context block height unless explicitly defined in the constructor.

    For example, assume that we index an ERC721 contract. Typescript ABI module generated with `squid-evm-typegen` will contain the following class:

    ```typescript theme={"system"}
    export class Contract extends ContractBase {
      //...
      balanceOf(owner: string): Promise<ethers.BigNumber> {
        return this.call('balanceOf', [owner])
      }
      //...
    }
    ```

    Now suppose we want to query our contract from the batch handler. To create a `Contract` pass the context object and the current `Block` to its constructor, then query the contract state at that block:

    ```ts theme={"system"}
    // ...
    const CONTRACT_ADDRESS = '0xb654611f84a8dc429ba3cb4fda9fad236c505a1a'

    processor.run(new TypeormDatabase(), async ctx => {
      for (const block of ctx.blocks) { 
        const contract = new abi.Contract(ctx, block.header, CONTRACT_ADDRESS)
        // query the contract state at the current block
        const uri = await contract.balanceOf('0xd8da6bf26964af9d7eed9e03e53415d37aa96045')
        // ...
      }
    })
    ```

    ## Batch state queries

    The [MakerDAO Multicall contract](https://github.com/makerdao/multicall) was designed to batch multiple state queries into a single contract call. In the context of indexing, it normally significantly improves the indexing speed since JSON RPC calls are typically the bottleneck.

    Multicall contracts are deployed in many EVM chains, see the [contract repo](https://github.com/makerdao/multicall) for addresses. You can use any of them with a `multicall` Typescript module that is generated when running `squid-evm-typegen` with `--multicall` option. The module exports a `Multicall` class with this method:

    ```ts theme={"system"}
    tryAggregate<Args extends any[], R>(
      func: Func<Args, {}, R>,
      calls: [address: string, args: Args][],
      paging?: number
    ): Promise<MulticallResult<R>[]>
    ```

    The arguments are as follows:

    * `func`: the contract function to be called
    * `calls`: an array of tuples `[contractAddress: string, args]`. Each specified contract will be called with the specified arguments.
    * `paging` an (optional) argument for the maximal number of calls to be batched into a single JSON PRC request. Note that large page sizes may cause timeouts.

    A typical usage is as follows:

    ```ts title="src/main.ts" theme={"system"}
    // generated by evm-typegen
    import { functions } from './abi/mycontract'
    import { Multicall } from './abi/multicall'

    const MY_CONTRACT = '0xac5c7493036de60e63eb81c5e9a440b42f47ebf5'
    const MULTICALL_CONTRACT = '0x5ba1e12693dc8f9c48aad8770482f4739beed696'

    processor.run(new TypeormDatabase(), async (ctx) => {
      for (let c of ctx.blocks) {
        // some logic
      }
      const lastBlock = ctx.blocks[ctx.blocks.length - 1]
      const multicall = new Multicall(
        ctx,
        lastBlock,
        MULTICALL_CONTRACT
      )
      // call MY_CONTRACT.myContractMethod('foo') and MY_CONTRACT.myContractMethod('bar')
      const args = ['foo', 'bar']
      const results = await multicall.tryAggregate(
        functions.myContractMethod,
        args.map(a => [MY_CONTRACT, a]) as [string, any[]],
        100
      )

      results.forEach((res, i) => {
        if (res.success) {
          ctx.log.info(`Result for argument ${args[i]} is ${res.value}`)
        }
      })
    })
    ```
  </Tab>

  <Tab title="squid-substrate-typegen">
    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 gRPC client to the chain node accessible via `ctx._chain`.
    It exposes low-level methods for accessing the storage. However, the recommended way to query the storage is with type-safe wrappers generated with `squid-substrate-typegen`.

    Substrate typegen tool exposes storage access wrappers at `src/types/storage.ts`. The wrappers follow the [general naming pattern](/en/sdk/squid-sdk/resources/tools/typegen/generation#typescript-wrappers) used by Substrate typegen:

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

    with all identifiers lowerCamelCased. Each wrapper exposes a generated `get()` query method and, if available, methods for multi-key queries, listing keys, key-value pairs and retrieving the default value.

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

    Here is an example of one such 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][]>
    }
    ```

    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)`

    ### Example

    ```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}`)
        }
      }
    })
    ```
  </Tab>

  <Tab title="squid-ink-typegen">
    The generated `Contract` class provides facades for all state calls that don't mutate the contract state. The info about the state mutability is taken from the contract metadata.

    ```ts 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])
        }
    }
    ```

    ### Example

    ```ts 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)
        }
      }
    })
    ```
  </Tab>
</Tabs>
