import { Abi, AbiEvent, Hex } from 'ox' import { describe, expect, test } from 'vp/test' import { wagmiContractConfig } from '../../../test/constants/abis.js' import { address } from '../../../test/constants/addresses.js' import { anvilMainnet } from '../../../test/prool.js' describe('assertArgs', () => { test('default', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) AbiEvent.assertArgs(abiEvent, args, { from: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', value: 1n, }) }) test('default', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed, address indexed, uint256)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) AbiEvent.assertArgs(abiEvent, args, [ '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', 1n, ]) }) test('error: args mismatch, named', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], }) expect(() => AbiEvent.assertArgs(abiEvent, args, { from: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ad', to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', value: 1n, }), ).toThrowErrorMatchingInlineSnapshot(` [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments. Event: event Transfer(address indexed from, address indexed to, uint256 value) Expected Arguments: from: 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC to: 0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad value: 1 Given Arguments: from: 0xa5cc3c03994db5b0d9a5eedd10cabab0813678ad to: 0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac value: 1] `) }) test('error: args mismatch, unnamed', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed, address indexed, uint256)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(() => AbiEvent.assertArgs(abiEvent, args, [ '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ad', ]), ).toThrowErrorMatchingInlineSnapshot(` [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments. Event: event Transfer(address indexed, address indexed, uint256) Expected Arguments: 0: 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC 1: 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC 2: 1 Given Arguments: 0: 0xa5cc3c03994db5b0d9a5eedd10cabab0813678ad] `) }) test('error: args mismatch, string', () => { const abiEvent = AbiEvent.from('event Transfer(string indexed a)') const args = AbiEvent.decode(abiEvent, { topics: [ '0x7cebee4ee226a36ff8751d9d69bb8265f5138c825f8c25d7ebdd60d972ffe5be', '0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8', ], }) expect(() => AbiEvent.assertArgs(abiEvent, args, { a: '0xdeadbeef', }), ).toThrowErrorMatchingInlineSnapshot(` [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments. Event: event Transfer(string indexed a) Expected Arguments: a: 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8 Given Arguments: a: 0xdeadbeef] `) }) test('error: input not found, named', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(() => AbiEvent.assertArgs(abiEvent, args, { // @ts-expect-error a: 'b', from: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ad', to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', value: 1n, }), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.InputNotFoundError: Parameter "a" not found on \`event Transfer(address indexed from, address indexed to, uint256 value)\`.]`, ) }) test('error: input not found, unnamed', () => { const abiEvent = AbiEvent.from( 'event Transfer(address indexed, address indexed, uint256)', ) const args = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(() => // @ts-expect-error AbiEvent.assertArgs(abiEvent, args, [ '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', 1n, 1n, ]), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.InputNotFoundError: Parameter "3" not found on \`event Transfer(address indexed, address indexed, uint256)\`.]`, ) }) test('error: provided args, but no actual event args', () => { const abiEvent = AbiEvent.from('event Transfer()') const args = AbiEvent.decode(abiEvent, { topics: [ '0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0', ], }) expect(() => // @ts-expect-error AbiEvent.assertArgs(abiEvent, args, { from: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678az', to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', value: 1n, }), ).toThrowErrorMatchingInlineSnapshot(` [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments. Event: event Transfer() Expected Arguments: None Given Arguments: from: 0xa5cc3c03994db5b0d9a5eedd10cabab0813678az to: 0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac value: 1] `) }) }) describe('decode', () => { test('behavior: named', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const decoded = AbiEvent.decode(transfer, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, } `) }) test('behavior: unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed, address indexed, uint256)', ) const decoded = AbiEvent.decode(transfer, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` [ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", 1n, ] `) }) test('behavior: named + unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256)', ) const decoded = AbiEvent.decode(transfer, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` { "2": 1n, "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", } `) }) test('behavior: named + unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed, uint256 value)', ) const decoded = AbiEvent.decode(transfer, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` { "1": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, } `) }) test('behavior: named + unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed, uint256 value, uint256)', ) const decoded = AbiEvent.decode(transfer, { data: '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001', topics: [ '0x9ed053bb818ff08b8353cd46f78db1f0799f31c9e4458fdb425c10eccd2efc44', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` { "1": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "3": 1n, "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, } `) }) test('behavior: string inputs', () => { const transfer = AbiEvent.from('event Transfer(string indexed a)') const decoded = AbiEvent.decode(transfer, { topics: [ '0x7cebee4ee226a36ff8751d9d69bb8265f5138c825f8c25d7ebdd60d972ffe5be', '0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8', ], }) expect(decoded).toMatchInlineSnapshot(` { "a": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8", } `) }) test('behavior: unnamed, non-indexed input before indexed input (array mode)', () => { // Declaration order (uint256, bool indexed) differs from indexed-subset // order (bool is the only indexed input). Args must still come back in // declaration order, not indexed-subset order. const foo = AbiEvent.from('event Foo(uint256, bool indexed)') const decoded = AbiEvent.decode(foo, { data: '0x0000000000000000000000000000000000000000000000000000000000000111', topics: [ '0x79c52e97493a8f32348c3cf1ebfe4a8dfaeb083ca12cddd87b5d9f7c00d3ccaa', '0x0000000000000000000000000000000000000000000000000000000000000001', ], }) expect(decoded).toMatchInlineSnapshot(` [ 273n, true, ] `) }) test('behavior: named + unnamed, indexed input interleaved with non-indexed (mixed mode)', () => { // `a` (indexed) and the trailing unnamed `address` (indexed) are not a // contiguous prefix of declaration order — a non-indexed `bool` sits // between them. All three values must be present and at the correct // declaration-order keys; none may be silently dropped or overwritten. const foo = AbiEvent.from( 'event Foo(uint256 indexed a, bool, address indexed)', ) const decoded = AbiEvent.decode(foo, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xbf5963a29fe665781e91d832989689110056ee09e32656ea57265dbb1084006e', '0x0000000000000000000000000000000000000000000000000000000000000aaa', '0x00000000000000000000000000cccccccccccccccccccccccccccccccccccccc', ], }) expect(decoded).toMatchInlineSnapshot(` { "1": true, "2": "0x00CCCCCCccCcCccCCcccCCcccCcCcCccCcCcCCcc", "a": 2730n, } `) }) test('error: topics mismatch, named', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address to, uint256 indexed value)', ) expect(() => AbiEvent.decode(transfer, { topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.TopicsMismatchError: Expected a topic for indexed event parameter "value" for "event Transfer(address indexed from, address to, uint256 indexed value)".]`, ) }) test('error: topics mismatch, unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed, address, uint256 indexed)', ) expect(() => AbiEvent.decode(transfer, { topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.TopicsMismatchError: Expected a topic for indexed event parameter for "event Transfer(address indexed, address, uint256 indexed)".]`, ) }) test('error: data mismatch', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address to, uint256 value)', ) expect(() => AbiEvent.decode(transfer, { data: '0x0000000000000000000000000000000000000000000000000000000023c34600', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', '0x00000000000000000000000070e8a65d014918798ba424110d5df658cde1cc58', ], }), ).toThrowErrorMatchingInlineSnapshot( ` [AbiEvent.DataMismatchError: Data size of 32 bytes is too small for non-indexed event parameters. Non-indexed Parameters: (address to, uint256 value) Data: 0x0000000000000000000000000000000000000000000000000000000023c34600 (32 bytes)] `, ) }) test('error: data mismatch', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address to, uint256 value)', ) expect(() => AbiEvent.decode(transfer, { topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', '0x00000000000000000000000070e8a65d014918798ba424110d5df658cde1cc58', ], }), ).toThrowErrorMatchingInlineSnapshot( ` [AbiEvent.DataMismatchError: Data size of 0 bytes is too small for non-indexed event parameters. Non-indexed Parameters: (address to, uint256 value) Data: 0x (0 bytes)] `, ) }) test('error: invalid data size', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) expect(() => AbiEvent.decode(transfer, { data: '0x01', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045', '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', ], }), ).toThrowErrorMatchingInlineSnapshot( ` [AbiEvent.DataMismatchError: Data size of 1 bytes is too small for non-indexed event parameters. Non-indexed Parameters: (uint256 value) Data: 0x01 (1 bytes)] `, ) }) test('error: invalid boolean', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, bool sender)', ) expect(() => AbiEvent.decode(transfer, { data: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', topics: [ '0x3da3cd3cf420c78f8981e7afeefa0eab1f0de0eb56e78ad9ba918ed01c0b402f', '0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045', '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', ], }), ).toThrowErrorMatchingInlineSnapshot( ` [Bytes.InvalidBytesBooleanError: Bytes value \`221,242,82,173,27,226,200,155,105,194,176,104,252,55,141,170,149,43,167,241,99,196,161,22,40,245,90,77,245,35,179,239\` is not a valid boolean. The bytes array must contain a single byte of either a \`0\` or \`1\` value.] `, ) }) test('error: event selector topic mismatch', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, bool sender)', ) expect(() => AbiEvent.decode(transfer, { topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045', '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', ], }), ).toThrowErrorMatchingInlineSnapshot( ` [AbiEvent.SelectorTopicMismatchError: topics[0]="0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" does not match the expected topics[0]="0x3da3cd3cf420c78f8981e7afeefa0eab1f0de0eb56e78ad9ba918ed01c0b402f". Event: event Transfer(address indexed from, address indexed to, bool sender) Selector: 0x3da3cd3cf420c78f8981e7afeefa0eab1f0de0eb56e78ad9ba918ed01c0b402f] `, ) }) test('behavior: overload with abi', () => { const abi = Abi.from([ 'event Transfer(address indexed from, address indexed to, uint256 value)', ]) const log = { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], } as const // Test both overload patterns const abiEvent = AbiEvent.fromAbi(abi, 'Transfer') const decoded1 = AbiEvent.decode(abiEvent, log) const decoded2 = AbiEvent.decode(abi, 'Transfer', log) expect(decoded1).toEqual(decoded2) expect(decoded2).toMatchInlineSnapshot(` { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, } `) }) test('behavior: overload with hex selector', () => { const abi = Abi.from([ 'event Transfer(address indexed from, address indexed to, uint256 value)', ]) const log = { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], } as const // Test with hex selector const decoded = AbiEvent.decode( abi, '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', log, ) expect(decoded).toMatchInlineSnapshot(` { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, } `) }) test('behavior: anonymous event', () => { const abiEvent = AbiEvent.from({ type: 'event', name: 'Transfer', anonymous: true, inputs: [ { name: 'from', type: 'address', indexed: true }, { name: 'to', type: 'address', indexed: true }, { name: 'value', type: 'uint256', indexed: false }, ], }) const decoded = AbiEvent.decode(abiEvent, { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], }) expect(decoded).toMatchInlineSnapshot(` { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "value": 1n, } `) }) }) describe('decodeLog', () => { test('behavior: decodes event from selector topic', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const decoded = AbiEvent.decodeLog([transfer], { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }) expect(decoded).toMatchInlineSnapshot(` { "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, }, "event": { "hash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "inputs": [ { "indexed": true, "name": "from", "type": "address", }, { "indexed": true, "name": "to", "type": "address", }, { "name": "value", "type": "uint256", }, ], "name": "Transfer", "type": "event", }, } `) }) test('error: selector topic not found', () => { const transfer = AbiEvent.from('event Transfer(address indexed from)') expect(() => AbiEvent.decodeLog([transfer], { data: '0x', topics: [] })) .toThrowErrorMatchingInlineSnapshot(` [AbiEvent.SelectorTopicNotFoundError: Selector topic not found.] `) }) }) describe('extractLogs', () => { test('behavior: decodes matching logs', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const log = { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], } as const const decoded = AbiEvent.extractLogs([transfer], [log]) expect(decoded).toMatchInlineSnapshot(` [ { "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "value": 1n, }, "data": "0x0000000000000000000000000000000000000000000000000000000000000001", "eventName": "Transfer", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", ], }, ] `) }) test('behavior: skips non-matching logs in strict mode', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const approval = AbiEvent.from( 'event Approval(address indexed owner, address indexed spender, uint256 value)', ) const decoded = AbiEvent.extractLogs( [transfer], [ { data: '0x', topics: [AbiEvent.getSelector(approval)], }, { data: '0x', topics: [], }, ], ) expect(decoded).toMatchInlineSnapshot(`[]`) }) test('behavior: filters by event name', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const approval = AbiEvent.from( 'event Approval(address indexed owner, address indexed spender, uint256 value)', ) const decoded = AbiEvent.extractLogs( [transfer, approval], [ { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], }, { data: '0x0000000000000000000000000000000000000000000000000000000000000002', topics: [ AbiEvent.getSelector(approval), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], }, ], { eventName: 'Approval' }, ) expect(decoded).toMatchInlineSnapshot(` [ { "args": { "owner": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "spender": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "value": 2n, }, "data": "0x0000000000000000000000000000000000000000000000000000000000000002", "eventName": "Approval", "topics": [ "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad", ], }, ] `) }) test('behavior: filters by arguments', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const decoded = AbiEvent.extractLogs( [transfer], [ { data: '0x0000000000000000000000000000000000000000000000000000000000000001', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], }, { data: '0x0000000000000000000000000000000000000000000000000000000000000002', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }, ], { args: { from: '0xa5CC3c03994Db5b0D9a5eeDd10CaBaB0813678Ac', }, }, ) expect(decoded).toMatchInlineSnapshot(` [ { "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "value": 1n, }, "data": "0x0000000000000000000000000000000000000000000000000000000000000001", "eventName": "Transfer", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad", ], }, ] `) }) test('behavior: tries ABI events with matching selectors', () => { const erc20Transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const erc721Transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)', ) const decoded = AbiEvent.extractLogs( [erc20Transfer, erc721Transfer], [ { data: '0x', topics: [ AbiEvent.getSelector(erc721Transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', '0x0000000000000000000000000000000000000000000000000000000000000001', ], }, ], ) expect(decoded).toMatchInlineSnapshot(` [ { "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "tokenId": 1n, }, "data": "0x", "eventName": "Transfer", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad", "0x0000000000000000000000000000000000000000000000000000000000000001", ], }, ] `) }) test('behavior: non-strict mode decodes missing indexed topics from data', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const decoded = AbiEvent.extractLogs( [transfer], [ { data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad0000000000000000000000000000000000000000000000000000000000000001', topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', ], }, ], { strict: false }, ) expect(decoded).toMatchInlineSnapshot(` [ { "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "value": 1n, }, "data": "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad0000000000000000000000000000000000000000000000000000000000000001", "eventName": "Transfer", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", ], }, ] `) }) test('behavior: non-strict mode returns partial logs when decoding fails', () => { const transfer = AbiEvent.from('event Transfer(address indexed from)') const decoded = AbiEvent.extractLogs( [transfer], [ { data: '0x', topics: [AbiEvent.getSelector(transfer), '0xdead'], }, ], { strict: false }, ) expect(decoded).toMatchInlineSnapshot(` [ { "args": {}, "data": "0x", "eventName": "Transfer", "topics": [ "0x2d339b1e3334d3f43e7aa6d5b1fa3ca5e4228b2dd547d1710c726019d98e53fa", "0xdead", ], }, ] `) }) test('behavior: formats RPC logs', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const decoded = AbiEvent.extractLogs( [transfer], [ { address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2', blockHash: '0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4', blockNumber: '0x12d846c', data: '0x0000000000000000000000000000000000000000000000000000000000000001', logIndex: '0x10f', removed: false, topics: [ AbiEvent.getSelector(transfer), '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad', ], transactionHash: '0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93', transactionIndex: '0x91', }, ], ) expect(decoded).toMatchInlineSnapshot(` [ { "address": "0xfba3912ca04dd458c843e2ee08967fc04f3579c2", "args": { "from": "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC", "to": "0xa5Cc3C03994DB5B0d9a5EEdD10CaBab0813678ad", "value": 1n, }, "blockHash": "0xabe69134e80a12f6a93d0aa18215b5b86c2fb338bae911790ca374a8716e01a4", "blockNumber": 19760236n, "blockTimestamp": undefined, "data": "0x0000000000000000000000000000000000000000000000000000000000000001", "eventName": "Transfer", "logIndex": 271, "removed": false, "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac", "0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ad", ], "transactionHash": "0xcfa52db0bc2cb5bdcb2c5bd8816df7a2f018a0e3964ab1ef4d794cf327966e93", "transactionIndex": 145, }, ] `) }) }) describe('encode', () => { test('default', () => { const transfer = AbiEvent.from('event Transfer()') expect(AbiEvent.encode(transfer)).toMatchInlineSnapshot(` { "topics": [ "0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0", ], } `) }) test('behavior: no hash', () => { const transfer = AbiEvent.from('event Transfer()') expect(AbiEvent.encode({ ...transfer, hash: undefined })) .toMatchInlineSnapshot(` { "topics": [ "0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0", ], } `) }) test('behavior: multiple inputs, no args', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed a, address indexed b, uint256 c)', ) expect(AbiEvent.encode(transfer)).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", ], } `) }) test('behavior: multiple inputs, with args, named', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed a, address indexed b, uint256 c)', ) expect( AbiEvent.encode(transfer, { a: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", null, ], } `) expect( AbiEvent.encode(transfer, { b: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", null, "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: '0x0000000000000000000000000000000000000000', b: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: null, b: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", null, "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: ['0x0000000000000000000000000000000000000000', address.vitalik], b: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045", ], "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) }) test('behavior: multiple inputs, with args, unnamed', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed, address indexed, uint256 )', ) expect( AbiEvent.encode(transfer, ['0x0000000000000000000000000000000000000000']), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", null, ], } `) expect( AbiEvent.encode(transfer, [ null, '0x0000000000000000000000000000000000000000', ]), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", null, "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, [ '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', ]), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, [ ['0x0000000000000000000000000000000000000000', address.vitalik], '0x0000000000000000000000000000000000000000', ]), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045", ], "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) }) test('behavior: multiple inputs, with args, partially named', () => { const transfer = AbiEvent.from( 'event Transfer(address indexed a, address indexed, uint256 c)', ) expect( AbiEvent.encode(transfer, { a: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", null, ], } `) expect( AbiEvent.encode(transfer, { 1: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", null, "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: '0x0000000000000000000000000000000000000000', 1: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: null, 1: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", null, "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) expect( AbiEvent.encode(transfer, { a: ['0x0000000000000000000000000000000000000000', address.vitalik], 1: '0x0000000000000000000000000000000000000000', }), ).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045", ], "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) }) test('behavior: string inputs', () => { const transfer = AbiEvent.from('event Transfer(string indexed a, string b)') expect( AbiEvent.encode(transfer, { a: 'hello', }), ).toMatchInlineSnapshot(` { "topics": [ "0x89525573e05dbc5f7f7f72e98f8145459e8b183e54c819fa7029f09a04115d89", "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8", ], } `) }) test('behavior: leading non-indexed inputs', () => { const transfer = AbiEvent.from( 'event Transfer(uint256 a, string indexed b)', ) expect( AbiEvent.encode(transfer, { b: 'hello', }), ).toMatchInlineSnapshot(` { "topics": [ "0x9060fea662832699cca863409e283b48eb088414dc780c4d43afe69caefee4b5", "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8", ], } `) }) test('behavior: network', async () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 indexed value)', ) const { topics } = AbiEvent.encode(transfer) const logs = await anvilMainnet.request({ method: 'eth_getLogs', params: [ { address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2', fromBlock: Hex.fromNumber(19760235n), toBlock: Hex.fromNumber(19760240n), topics, }, ], }) expect(AbiEvent.decode(transfer, logs[0]!)).toMatchInlineSnapshot(` { "from": "0x0000000000000000000000000000000000000000", "to": "0x0C04D9e9278EC5e4D424476D3Ebec70Cb5d648D1", "value": 603n, } `) }) test('error: tuple input', () => { const transfer = AbiEvent.from( 'event Transfer((string) indexed a, string b)', ) expect(() => AbiEvent.encode(transfer, { a: ['hello'], }), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.FilterTypeNotSupportedError: Filter type "tuple" is not supported.]`, ) }) test('error: array input', () => { const transfer = AbiEvent.from( 'event Transfer(uint256[] indexed a, string b)', ) expect(() => AbiEvent.encode(transfer, { a: [1n], }), ).toThrowErrorMatchingInlineSnapshot( `[AbiEvent.FilterTypeNotSupportedError: Filter type "uint256[]" is not supported.]`, ) }) test('behavior: network', async () => { const transfer = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) const { topics } = AbiEvent.encode(transfer) const logs = await anvilMainnet.request({ method: 'eth_getLogs', params: [{ topics }], }) expect(AbiEvent.decode(transfer, logs[0]!)).toMatchInlineSnapshot(` { "from": "0x634cf119d1964b88a426E1E782Bd09f37b51d949", "to": "0xB77c2290C5e5ACD8Ca4778876b3CAaE593741BAB", "value": 714357880932609n, } `) }) test('https://github.com/wevm/viem/issues/3278', () => { const event = AbiEvent.from('event test(uint32 indexed val)') expect( AbiEvent.encode(event, { val: 0, }), ).toMatchInlineSnapshot(` { "topics": [ "0xe3cff634ef3ac1857ee74821b8b4103c803384af6152771eef3a2a92bdda6db6", "0x0000000000000000000000000000000000000000000000000000000000000000", ], } `) }) test('behavior: overload with abi', () => { const abi = Abi.from([ 'event Transfer(address indexed from, address indexed to, uint256 value)', ]) // Test both overload patterns const abiEvent = AbiEvent.fromAbi(abi, 'Transfer') const result1 = AbiEvent.encode(abiEvent, { from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', }) const result2 = AbiEvent.encode(abi, 'Transfer', { from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', }) expect(result1).toEqual(result2) expect(result2).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266", "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", ], } `) }) test('behavior: overload with abi - no args', () => { const abi = Abi.from(['event Transfer()']) // Test both overload patterns const abiEvent = AbiEvent.fromAbi(abi, 'Transfer') const result1 = AbiEvent.encode(abiEvent) const result2 = AbiEvent.encode(abi, 'Transfer') expect(result1).toEqual(result2) expect(result2).toMatchInlineSnapshot(` { "topics": [ "0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0", ], } `) }) test('behavior: overload with array args', () => { const abi = Abi.from([ 'event Transfer(address indexed, address indexed, uint256)', ]) // Test both overload patterns with unnamed args const abiEvent = AbiEvent.fromAbi(abi, 'Transfer') const result1 = AbiEvent.encode(abiEvent, [ '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', ]) const result2 = AbiEvent.encode(abi, 'Transfer', [ '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', ]) expect(result1).toEqual(result2) expect(result2).toMatchInlineSnapshot(` { "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266", "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", ], } `) }) }) describe('format', () => { test('default', () => { const transfer = AbiEvent.from({ type: 'event', name: 'Transfer', inputs: [ { name: 'from', type: 'address', indexed: true }, { name: 'to', type: 'address', indexed: true }, { name: 'value', type: 'uint256' }, ], }) const formatted = AbiEvent.format(transfer) expect(formatted).toMatchInlineSnapshot( `"event Transfer(address indexed from, address indexed to, uint256 value)"`, ) }) }) describe('from', () => { test('default', () => { { const abiItem = AbiEvent.from({ type: 'event', name: 'Transfer', inputs: [ { name: 'from', type: 'address', indexed: true }, { name: 'to', type: 'address', indexed: true }, { name: 'value', type: 'uint256' }, ], }) expect(abiItem).toMatchInlineSnapshot(` { "hash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "inputs": [ { "indexed": true, "name": "from", "type": "address", }, { "indexed": true, "name": "to", "type": "address", }, { "name": "value", "type": "uint256", }, ], "name": "Transfer", "type": "event", } `) } { const abiItem = AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ) expect(abiItem).toMatchInlineSnapshot(` { "hash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "inputs": [ { "indexed": true, "name": "from", "type": "address", }, { "indexed": true, "name": "to", "type": "address", }, { "name": "value", "type": "uint256", }, ], "name": "Transfer", "type": "event", } `) } }) test('options: prepare', () => { const abiItem = AbiEvent.from( { type: 'event', name: 'Transfer', inputs: [ { name: 'from', type: 'address', indexed: true }, { name: 'to', type: 'address', indexed: true }, { name: 'value', type: 'uint256' }, ], }, { prepare: false }, ) expect(abiItem).toMatchInlineSnapshot(` { "inputs": [ { "indexed": true, "name": "from", "type": "address", }, { "indexed": true, "name": "to", "type": "address", }, { "name": "value", "type": "uint256", }, ], "name": "Transfer", "type": "event", } `) }) }) describe('fromAbi', () => { test('default', () => { expect(AbiEvent.fromAbi(wagmiContractConfig.abi, 'Approval')) .toMatchInlineSnapshot(` { "anonymous": false, "hash": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", "inputs": [ { "indexed": true, "name": "owner", "type": "address", }, { "indexed": true, "name": "approved", "type": "address", }, { "indexed": true, "name": "tokenId", "type": "uint256", }, ], "name": "Approval", "type": "event", } `) }) test('behavior: prepare = false', () => { expect( AbiEvent.fromAbi(wagmiContractConfig.abi, 'Approval', { prepare: false, }), ).toMatchInlineSnapshot(` { "anonymous": false, "inputs": [ { "indexed": true, "name": "owner", "type": "address", }, { "indexed": true, "name": "approved", "type": "address", }, { "indexed": true, "name": "tokenId", "type": "uint256", }, ], "name": "Approval", "type": "event", } `) }) test('behavior: name (hash)', () => { const item = AbiEvent.fromAbi(wagmiContractConfig.abi, 'Approval') expect( AbiEvent.fromAbi(wagmiContractConfig.abi, AbiEvent.getSelector(item)), ).toMatchInlineSnapshot(` { "anonymous": false, "hash": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", "inputs": [ { "indexed": true, "name": "owner", "type": "address", }, { "indexed": true, "name": "approved", "type": "address", }, { "indexed": true, "name": "tokenId", "type": "uint256", }, ], "name": "Approval", "type": "event", } `) }) test('error: no matching name', () => { expect(() => // @ts-expect-error AbiEvent.fromAbi(wagmiContractConfig.abi, 'approve'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI event with name "approve" not found.]`, ) }) test('error: no matching name', () => { expect(() => AbiEvent.fromAbi([] as readonly unknown[], 'Approved'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "Approved" not found.]`, ) }) test('error: no matching data', () => { expect(() => AbiEvent.fromAbi([], '0xdeadbeef'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "0xdeadbeef" not found.]`, ) }) test('behavior: overloads', () => { const abi = Abi.from([ 'event Bar()', 'event Foo(address indexed)', 'event Foo(uint256 indexed)', ]) const item = AbiEvent.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xe773a60b784586770a963a70fa6ba2bdf31c462939b6ba36852ed45f5f722358", "inputs": [ { "indexed": true, "type": "address", }, ], "name": "Foo", "overloads": [ { "inputs": [ { "indexed": true, "type": "uint256", }, ], "name": "Foo", "type": "event", }, ], "type": "event", } `) }) test('behavior: overloads: no inputs', () => { const abi = Abi.from(['event Bar()', 'event Foo()', 'event Foo(uint256)']) const item = AbiEvent.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xbfb4ebcfff8f360b39de1de85df1edc256d63337b743120bf6e2e2144b973d38", "inputs": [], "name": "Foo", "type": "event", } `) }) test('overloads: no args', () => { const abi = Abi.from(['event Bar()', 'event Foo(uint256)', 'event Foo()']) const item = AbiEvent.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xbfb4ebcfff8f360b39de1de85df1edc256d63337b743120bf6e2e2144b973d38", "inputs": [], "name": "Foo", "type": "event", } `) }) test('behavior: overloads: different types', () => { const abi = Abi.from([ 'event Mint()', 'event Mint(uint256)', 'event Mint(string)', ]) const item = AbiEvent.fromAbi(abi, 'Mint') expect(item).toMatchInlineSnapshot(` { "hash": "0x34c73884fbbb790762253ae313e57da96c00670344647f0cb8d41ee92b9f1971", "inputs": [], "name": "Mint", "type": "event", } `) const item_2 = AbiEvent.fromAbi(abi, 'Mint', { args: [420n], }) expect(item_2).toMatchInlineSnapshot(` { "hash": "0x07883703ed0e86588a40d76551c92f8a4b329e3bf19765e0e6749473c1a84665", "inputs": [ { "type": "uint256", }, ], "name": "Mint", "type": "event", } `) const item_3 = AbiEvent.fromAbi(abi, 'Mint', { args: ['foo'], }) expect(item_3).toMatchInlineSnapshot(` { "hash": "0xc5e1d731c47dbd6a8c38e6ee9137792904eae9d20174034d1dc9a5781a0f855b", "inputs": [ { "type": "string", }, ], "name": "Mint", "type": "event", } `) }) test('behavior: overloads: ambiguious types', () => { expect(() => AbiEvent.fromAbi( Abi.from(['event Foo(address)', 'event Foo(bytes20)']), 'Foo', { args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'], }, ), ).toThrowErrorMatchingInlineSnapshot(` [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items. \`bytes20\` in \`Foo(bytes20)\`, and \`address\` in \`Foo(address)\` These types encode differently and cannot be distinguished at runtime. Remove one of the ambiguous items in the ABI.] `) expect(() => AbiEvent.fromAbi( Abi.from([ 'event Foo(string)', 'event Foo(uint)', 'event Foo(address)', ]), 'Foo', { args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'], }, ), ).toThrowErrorMatchingInlineSnapshot(` [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items. \`address\` in \`Foo(address)\`, and \`string\` in \`Foo(string)\` These types encode differently and cannot be distinguished at runtime. Remove one of the ambiguous items in the ABI.] `) expect( AbiEvent.fromAbi( Abi.from([ 'event Foo(string)', 'event Foo(uint)', 'event Foo(address)', ]), 'Foo', { // 21 bytes (invalid address) args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251eee'], }, ), ).toMatchInlineSnapshot(` { "hash": "0x9f0b7f1630bdb7d474466e2dfef0fb9dff65f7a50eec83935b68f77d0808f08a", "inputs": [ { "type": "string", }, ], "name": "Foo", "type": "event", } `) expect( AbiEvent.fromAbi( Abi.from([ 'event Foo(string)', 'event Foo(uint)', 'event Foo(address)', ]), 'Foo', { // non-hex (invalid address) args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251z'], }, ), ).toMatchInlineSnapshot(` { "hash": "0x9f0b7f1630bdb7d474466e2dfef0fb9dff65f7a50eec83935b68f77d0808f08a", "inputs": [ { "type": "string", }, ], "name": "Foo", "type": "event", } `) expect(() => AbiEvent.fromAbi( Abi.from([ 'event Foo(address)', 'event Foo(uint)', 'event Foo(string)', ]), 'Foo', { args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'], }, ), ).toThrowErrorMatchingInlineSnapshot(` [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items. \`string\` in \`Foo(string)\`, and \`address\` in \`Foo(address)\` These types encode differently and cannot be distinguished at runtime. Remove one of the ambiguous items in the ABI.] `) }) }) describe('getSelector', () => { test('default', () => { expect( AbiEvent.getSelector( 'event Transfer(address indexed from, address indexed to, uint256 value)', ), ).toEqual( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', ) expect( AbiEvent.getSelector( 'Transfer(address indexed from, address indexed to, uint256 value)', ), ).toEqual( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', ) }) test('behavior: from `AbiEvent`', () => { expect( AbiEvent.getSelector( AbiEvent.from( 'event Transfer(address indexed from, address indexed to, uint256 value)', ), ), ).toEqual( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', ) }) }) test('exports', () => { expect(Object.keys(AbiEvent)).toMatchInlineSnapshot(` [ "assertArgs", "decode", "decodeLog", "extractLogs", "encode", "format", "from", "fromAbi", "getSelector", "ArgsMismatchError", "InputNotFoundError", "DataMismatchError", "TopicsMismatchError", "SelectorTopicMismatchError", "SelectorTopicNotFoundError", "FilterTypeNotSupportedError", ] `) })