Skip to main content
Version: Current

Frontier EVM support


Method documentation is also available inline and can be accessed via suggestions in most IDEs.


Check out the Caveats section of this page to avoid common issues.

This section describes additional options available for Substrate chains with the Frontier EVM pallet like Astar. On ArrowSquid, use the frontier-evm template as the starting point.

The overall approach is to use the SubstrateBatchProcessor methods addEvmLog() and addEthereumTransaction() to request the required EVM data. The data can then be converted into a standard EVM format using the utils from the frontier package and decoded with utility classes generated by squid-evm-typegen.

Contract state can also be accessed via wrapped RPC queries using the classes provided by the squid-evm-typegen tool.


Subscribe to event logs

const processor = new SubstrateBatchProcessor()
.setGateway(lookupArchive('astar', {type: 'Substrate', release: 'ArrowSquid'}))
address: [
topic0: [],
extrinsic: true
event: {
phase: true
extrinsics: {
hash: true

Request all EVM calls to two contracts

to: [

Request all transfer(address,uint256) EVM calls on the network:

processor.addEthereumTransaction({sighash: ['0xa9059cbb']})

Parse events and transactions

const processor = new SubstrateBatchProcessor()
.setGateway(lookupArchive('astar', {type: 'Substrate'}))
.addEvmLog({}) TypeormDatabase(), async ctx => {
for (const block of ctx.blocks) {
for (const event of {
if ( === 'EVM.Log') {
// no need to supply any extra data to determine
// the runtime version: event has all necessary references
const {address, data, topics} = getEvmLog(event)

// process evm log data
for (const call of block.calls) {
if ('Ethereum.transact') {
const txn = getTransaction(call)
// process evm txn data

Access contract state

// ...
const CONTRACT_ADDRESS= "0xb654611f84a8dc429ba3cb4fda9fad236c505a1a" TypeormDatabase(), async ctx => {
for (const block of ctx.blocks) {
for (const event of {
if ( === "EVM.Log") {
const contract = new erc721.Contract(ctx, block, CONTRACT_ADDRESS);
// query the contract state
const uri = await contract.tokenURI(1137)

Factory contracts

It some cases the set of contracts to be indexed by the squid is not known in advance. For example, a DEX contract typically creates a new contract for each trading pair added, and each such trading contract is of interest.

While the set of handler subscriptions is static and defined at the processor creation, one can leverage the wildcard subscriptions and filter the contracts of interest in runtime. This pattern is described extensively in EVM documentation, but it can be used with EVM methods of SubstrateBatchProcessor as well. A (somewhat outdated) example is available in this archive repo.


  • If your use case does not require any Substrate-specific data (e.g. extrinsic hashes), use EvmBatchProcessor instead. EVM-only Subsquid Network datasets are available for all major EVM-on-Substrate chains.

  • Passing [] as a set of parameter values selects no data. Pass undefined for a wildcard selection:

    .addEvmLog({address: []}) // selects no events
    .addEvmLog({}) // selects all events
  • If contract address(es) supplied to the processor configuration methods are stored in any wide-scope variables, it is recommended to convert them to flat lower case. This precaution is necessary because same variable(s) are often reused in the batch handler for item filtration, and all contract addresses in the items are always in flat lower case.