import { commonAbis, evmEventDecoder, evmPortalStream } from '@subsquid/pipes/evm'
import { type MockPortal, readAll } from '@subsquid/pipes/testing'
import {
encodeEvent,
mockEvmPortalStream,
mockBlock,
resetMockBlockCounter,
} from '@subsquid/pipes/testing/evm'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
const ERC20_ABI = [
{
type: 'event' as const,
name: 'Transfer',
inputs: [
{ name: 'from', type: 'address', indexed: true },
{ name: 'to', type: 'address', indexed: true },
{ name: 'value', type: 'uint256', indexed: false },
],
},
] as const
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as const
const ALICE = '0x7a250d5630b4cf539739df2c5dacb4c659f2488d' as const
const BOB = '0xc82e11e709deb68f3631fc165ebd8b4e3fc3d18f' as const
describe('EVM pipe', () => {
let portal: MockPortal
beforeEach(() => {
resetMockBlockCounter()
})
afterEach(async () => {
await portal?.close()
})
it('decodes ERC20 transfers from mock blocks', async () => {
// 1. Encode events; args are fully typed from the ABI
const transfer = encodeEvent({
abi: ERC20_ABI,
eventName: 'Transfer',
address: USDC,
args: { from: ALICE, to: BOB, value: 1_000_000n },
})
// 2. Build mock blocks and serve them from a mock portal
portal = await mockEvmPortalStream({
blocks: [mockBlock({ transactions: [{ logs: [transfer] }] })],
})
// 3. Create the pipe exactly as in production, with the mock portal URL
const stream = evmPortalStream({
id: 'test',
portal: portal.url,
outputs: evmEventDecoder({
range: { from: 0, to: 1 },
events: { transfers: commonAbis.erc20.events.Transfer },
}),
}).pipe((batch) => batch.transfers)
// 4. Collect all output and assert
const transfers = await readAll(stream)
expect(transfers).toHaveLength(1)
expect(transfers[0].event.from).toBe(ALICE)
expect(transfers[0].event.value).toBe(1_000_000n)
expect(transfers[0].contract).toBe(USDC)
})
})