ERC20 Decoder
Decode USDC Transfer events. Use case: Decode ERC20 token transfers with typed event data.Copy
import {
evmPortalSource,
evmDecoder,
commonAbis,
} from "@subsquid/pipes/evm";
async function main() {
const source = evmPortalSource({
portal: "https://portal.sqd.dev/datasets/ethereum-mainnet",
});
const decoder = evmDecoder({
range: { from: 20000000, to: 20000100 },
contracts: ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"], // USDC
events: {
transfer: commonAbis.erc20.events.Transfer,
},
});
for await (const { data } of source.pipe(decoder)) {
for (const t of data.transfer) {
console.log({
from: t.event.from,
to: t.event.to,
value: t.event.value.toString(),
block: t.block.number,
tx: t.rawEvent.transactionHash,
});
}
}
}
void main();
Data Flow
Composite Decoder
Decode multiple event types simultaneously. Use case: Index ERC20 transfers and Uniswap swaps in one pipe.Copy
import {
evmPortalSource,
evmDecoder,
commonAbis,
} from "@subsquid/pipes/evm";
import * as uniswapAbi from "./abi/uniswap-v3-pool";
async function main() {
const source = evmPortalSource({
portal: "https://portal.sqd.dev/datasets/ethereum-mainnet",
});
const pipeline = source.pipeComposite({
usdc: evmDecoder({
range: { from: 20000000, to: 20000100 },
contracts: ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"],
events: {
transfer: commonAbis.erc20.events.Transfer,
},
}),
uniswap: evmDecoder({
range: { from: 20000000, to: 20000100 },
contracts: ["0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"],
events: {
swap: uniswapAbi.events.Swap,
},
}),
});
for await (const { data } of pipeline) {
console.log({
usdcTransfers: data.usdc.transfer.length,
uniswapSwaps: data.uniswap.swap.length,
});
}
}
void main();
Data Flow
Multiple Event Types
Decode Transfers and Approvals from same contract. Use case: Index multiple event types from one contract.Use
@subsquid/evm-typegen to generate typed ABIs instead of manually finding
raw event signatures. This approach provides type safety and eliminates the
need to look up topic0 hashes. See the Custom ABI section
below.Copy
import {
evmPortalSource,
evmDecoder,
commonAbis,
} from "@subsquid/pipes/evm";
async function main() {
const source = evmPortalSource({
portal: "https://portal.sqd.dev/datasets/ethereum-mainnet",
});
const decoder = evmDecoder({
range: { from: 20000000, to: 20000100 },
contracts: ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"],
events: {
transfer: commonAbis.erc20.events.Transfer,
approval: commonAbis.erc20.events.Approval,
},
});
for await (const { data } of source.pipe(decoder)) {
console.log({
transfers: data.transfer.length,
approvals: data.approval.length,
});
for (const t of data.transfer) {
console.log(
`Transfer: ${t.event.from} -> ${t.event.to}: ${t.event.value}`
);
}
for (const a of data.approval) {
console.log(
`Approval: ${a.event.owner} approved ${a.event.spender}: ${a.event.value}`
);
}
}
}
void main();
Custom ABI
Generate and use custom ABIs. Use case: Index events from contracts with custom ABIs.Generate ABI
Copy
npx @subsquid/evm-typegen src/abi abi/MyContract.json
Use Generated ABI
Copy
import { evmPortalSource, evmDecoder } from "@subsquid/pipes/evm";
import * as myContractAbi from "./abi/MyContract";
async function main() {
const source = evmPortalSource({
portal: "https://portal.sqd.dev/datasets/ethereum-mainnet",
});
const decoder = evmDecoder({
range: { from: 20000000 },
contracts: ["0x..."],
events: {
myEvent: myContractAbi.events.MyCustomEvent,
anotherEvent: myContractAbi.events.AnotherEvent,
},
});
for await (const { data } of source.pipe(decoder)) {
console.log(data.myEvent);
console.log(data.anotherEvent);
}
}
void main();

