UNPKG

ox

Version:

Ethereum Standard Library

1,145 lines (1,051 loc) 31.2 kB
import { Abi, AbiError, AbiFunction, AbiItem } from 'ox' import { describe, expect, test } from 'vp/test' import { Errors } from '../../../contracts/generated.js' import { seaportContractConfig } from '../../../test/constants/abis.js' import { address } from '../../../test/constants/addresses.js' import { anvilMainnet } from '../../../test/prool.js' describe('decode', () => { test('behavior: no args', () => { const error = AbiError.from('error InvalidSignature()') const data = AbiError.encode(error) expect(data).toMatchInlineSnapshot(`"0x8baa579f"`) expect(AbiError.decode(error, data)).toEqual(undefined) }) test('behavior: single arg', () => { const error = AbiError.from('error InvalidSignature(uint8 yParity)') const data = AbiError.encode(error, [1]) expect(data).toMatchInlineSnapshot( `"0x480770df0000000000000000000000000000000000000000000000000000000000000001"`, ) const decoded = AbiError.decode(error, data) expect(decoded).toEqual(1) }) test('behavior: multiple args', () => { const error = AbiError.from('error Example(uint r, uint s, uint8 yParity)') const data = AbiError.encode(error, [420n, 69n, 1]) expect(data).toMatchInlineSnapshot( `"0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"`, ) const decoded = AbiError.decode(error, data) expect(decoded).toEqual([420n, 69n, 1]) }) test('options: checksumAddress = false', () => { const error = AbiError.from('error Unauthorized(address account)') const data = AbiError.encode(error, [address.vitalik]) expect(AbiError.decode(error, data)).toMatchInlineSnapshot( `"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"`, ) expect( AbiError.decode(error, data, { checksumAddress: false }), ).toMatchInlineSnapshot(`"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"`) }) test('behavior: as = Object', () => { const error = AbiError.from('error Example(uint r, uint s, uint8 yParity)') const data = AbiError.encode(error, [420n, 69n, 1]) expect(data).toMatchInlineSnapshot( `"0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"`, ) const decoded = AbiError.decode(error, data, { as: 'Object' }) expect(decoded).toEqual({ r: 420n, s: 69n, yParity: 1, }) }) test('behavior: as = Object, single arg', () => { const error = AbiError.from('error Example(uint8 yParity)') const data = AbiError.encode(error, [1]) expect(data).toMatchInlineSnapshot( `"0x1e9dde100000000000000000000000000000000000000000000000000000000000000001"`, ) const decoded = AbiError.decode(error, data, { as: 'Object' }) expect(decoded).toEqual(1) }) test('error: invalid data', () => { const error = AbiError.from('error Example(uint256 a)') expect(() => AbiError.decode(error, '0xaaa'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.InvalidSelectorSizeError: Selector size is invalid. Expected 4 bytes. Received 2 bytes ("0xaaa").]`, ) }) describe('behavior: network', async () => { const hash = await anvilMainnet.request({ method: 'eth_sendTransaction', params: [ { data: Errors.bytecode.object, }, ], }) await anvilMainnet.request({ method: 'anvil_mine', params: ['0x1', '0x0'], }) const { contractAddress } = (await anvilMainnet.request({ method: 'eth_getTransactionReceipt', params: [hash], }))! const abi = Abi.from(Errors.abi) test('solidity `Error`', async () => { const result = await anvilMainnet .request({ method: 'eth_call', params: [ { data: AbiFunction.encodeData( AbiFunction.fromAbi(abi, 'revertRead'), ), to: contractAddress, }, ], }) .catch((error) => { const errorItem = AbiError.fromAbi(abi, error.data.data) const value = AbiError.decode(errorItem, error.data.data) return [errorItem, value] }) expect(result).toMatchInlineSnapshot(` [ { "hash": "0x08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa", "inputs": [ { "name": "message", "type": "string", }, ], "name": "Error", "type": "error", }, "This is a revert message", ] `) }) test('solidity `Panic` (assert)', async () => { const result = await anvilMainnet .request({ method: 'eth_call', params: [ { data: AbiFunction.encodeData( AbiFunction.fromAbi(abi, 'assertRead'), ), to: contractAddress, }, ], }) .catch((error) => { const errorItem = AbiError.fromAbi(abi, error.data.data) const value = AbiError.decode(errorItem, error.data.data) if (typeof value !== 'number') return return [errorItem, value, AbiError.panicReasons[value]] }) expect(result).toMatchInlineSnapshot(` [ { "hash": "0x25fba4f52ccf6f699393995e0f649c9072d088cffa43609495ffad9216c5b1dc", "inputs": [ { "name": "reason", "type": "uint8", }, ], "name": "Panic", "type": "error", }, 1, "An \`assert\` condition failed.", ] `) }) test('solidity `Panic` (overflow)', async () => { const result = await anvilMainnet .request({ method: 'eth_call', params: [ { data: AbiFunction.encodeData( AbiFunction.fromAbi(abi, 'overflowRead'), ), to: contractAddress, }, ], }) .catch((error) => { const errorItem = AbiError.fromAbi(abi, error.data.data) const value = AbiError.decode(errorItem, error.data.data) if (typeof value !== 'number') return return [errorItem, value, AbiError.panicReasons[value]] }) expect(result).toMatchInlineSnapshot(` [ { "hash": "0x25fba4f52ccf6f699393995e0f649c9072d088cffa43609495ffad9216c5b1dc", "inputs": [ { "name": "reason", "type": "uint8", }, ], "name": "Panic", "type": "error", }, 17, "Arithmetic operation resulted in underflow or overflow.", ] `) }) test('custom error', async () => { const result = await anvilMainnet .request({ method: 'eth_call', params: [ { data: AbiFunction.encodeData( AbiFunction.fromAbi(abi, 'complexCustomWrite'), ), to: contractAddress, }, ], }) .catch((error) => { const errorItem = AbiError.fromAbi(abi, error.data.data) const value = AbiError.decode(errorItem, error.data.data) return [errorItem, value] }) expect(result).toMatchInlineSnapshot(` [ { "hash": "0xdb731cf434b2ed4535c45e759ac81849e63af37b1fec522c9145652b5caee860", "inputs": [ { "components": [ { "internalType": "address", "name": "sender", "type": "address", }, { "internalType": "uint256", "name": "bar", "type": "uint256", }, ], "internalType": "struct Errors.Foo", "name": "foo", "type": "tuple", }, { "internalType": "string", "name": "message", "type": "string", }, { "internalType": "uint256", "name": "number", "type": "uint256", }, ], "name": "ComplexError", "type": "error", }, [ { "bar": 69n, "sender": "0x0000000000000000000000000000000000000000", }, "bugger", 69n, ], ] `) }) }) test('behavior: overload with abi', () => { const abi = Abi.from([ 'error InvalidSignature(uint r, uint s, uint8 yParity)', ]) const data = '0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001' // Test both overload patterns const abiError = AbiError.fromAbi(abi, 'InvalidSignature') const decoded1 = AbiError.decode(abiError, data) const decoded2 = AbiError.decode(abi, 'InvalidSignature', data) expect(decoded1).toEqual(decoded2) expect(decoded2).toEqual([420n, 69n, 1]) }) test('behavior: overload with options', () => { const abi = Abi.from([ 'error InvalidSignature(uint r, uint s, uint8 yParity)', ]) const data = '0xecde634900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001' // Test both overload patterns with options const abiError = AbiError.fromAbi(abi, 'InvalidSignature') const decoded1 = AbiError.decode(abiError, data, { as: 'Object' }) const decoded2 = AbiError.decode(abi, 'InvalidSignature', data, { as: 'Object', }) expect(decoded1).toEqual(decoded2) expect(decoded2).toEqual({ r: 420n, s: 69n, yParity: 1 }) }) }) describe('extract', () => { test('behavior: custom error', () => { const abi = Abi.from([ 'error InvalidSignature(uint r, uint s, uint8 yParity)', ]) const data = AbiError.encode(abi, 'InvalidSignature', [420n, 69n, 1]) expect(AbiError.extract(abi, data)).toMatchInlineSnapshot(` { "args": [ 420n, 69n, 1, ], "error": { "hash": "0xe466f0a53c37b5089ce66fd75a6718bd144152a536445d8822cc0425aed52ebe", "inputs": [ { "name": "r", "type": "uint256", }, { "name": "s", "type": "uint256", }, { "name": "yParity", "type": "uint8", }, ], "name": "InvalidSignature", "type": "error", }, } `) }) test('behavior: as = Object', () => { const abi = Abi.from([ 'error InvalidSignature(uint r, uint s, uint8 yParity)', ]) const data = AbiError.encode(abi, 'InvalidSignature', [420n, 69n, 1]) expect(AbiError.extract(abi, data, { as: 'Object' })) .toMatchInlineSnapshot(` { "args": { "r": 420n, "s": 69n, "yParity": 1, }, "error": { "hash": "0xe466f0a53c37b5089ce66fd75a6718bd144152a536445d8822cc0425aed52ebe", "inputs": [ { "name": "r", "type": "uint256", }, { "name": "s", "type": "uint256", }, { "name": "yParity", "type": "uint8", }, ], "name": "InvalidSignature", "type": "error", }, } `) }) test('behavior: single arg does not collapse args', () => { const abi = Abi.from(['error InvalidSignature(uint8 yParity)']) const data = AbiError.encode(abi, 'InvalidSignature', [1]) expect(AbiError.extract(abi, data)).toMatchInlineSnapshot(` { "args": [ 1, ], "error": { "hash": "0x480770dfc505483359f8914e589d0b76d7110062ebac15888f32c59220803b1e", "inputs": [ { "name": "yParity", "type": "uint8", }, ], "name": "InvalidSignature", "type": "error", }, } `) }) test('behavior: solidity Error', () => { const data = AbiError.encode(AbiError.solidityError, ['execution reverted']) expect(AbiError.extract([], data)).toMatchInlineSnapshot(` { "args": [ "execution reverted", ], "error": { "hash": "0x08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa", "inputs": [ { "name": "message", "type": "string", }, ], "name": "Error", "type": "error", }, } `) }) test('behavior: no args', () => { const abi = Abi.from(['error InvalidSignature()']) const data = AbiError.encode(abi, 'InvalidSignature') expect(AbiError.extract(abi, data)).toMatchInlineSnapshot(` { "args": undefined, "error": { "hash": "0x8baa579fce362245063d36f11747a89dd489c54795634fc673cc0e0db51fedc5", "inputs": [], "name": "InvalidSignature", "type": "error", }, } `) }) test('error: invalid data', () => { expect(() => AbiError.extract([], '0xaaa'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.InvalidSelectorSizeError: Selector size is invalid. Expected 4 bytes. Received 2 bytes ("0xaaa").]`, ) }) }) describe('encode', () => { test('default', () => { const error = AbiError.from('error Example()') expect(AbiError.encode(error)).toMatchInlineSnapshot(`"0xb085b9a5"`) }) test('behavior: with args', () => { const error = AbiError.from('error Example(uint256)') expect(AbiError.encode(error, [69420n])).toMatchInlineSnapshot( `"0xdbecc3720000000000000000000000000000000000000000000000000000000000010f2c"`, ) }) test('behavior: no hash', () => { const error = AbiError.from('error Example()') expect( AbiError.encode({ ...error, hash: undefined }), ).toMatchInlineSnapshot(`"0xb085b9a5"`) }) test('behavior: overload with abi', () => { const abi = Abi.from([ 'error InvalidSignature(uint r, uint s, uint8 yParity)', ]) // Test both overload patterns const abiError = AbiError.fromAbi(abi, 'InvalidSignature') const encoded1 = AbiError.encode(abiError, [420n, 69n, 1]) const encoded2 = AbiError.encode(abi, 'InvalidSignature', [420n, 69n, 1]) expect(encoded1).toEqual(encoded2) expect(encoded2).toMatchInlineSnapshot( `"0xe466f0a500000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"`, ) }) test('behavior: overload with abi - no args', () => { const abi = Abi.from(['error Example()']) // Test both overload patterns const abiError = AbiError.fromAbi(abi, 'Example') const encoded1 = AbiError.encode(abiError) const encoded2 = AbiError.encode(abi, 'Example') expect(encoded1).toEqual(encoded2) expect(encoded2).toMatchInlineSnapshot(`"0xb085b9a5"`) }) }) describe('format', () => { test('default', () => { const exampleError = AbiError.from({ type: 'error', name: 'Example', inputs: [ { name: 'spender', type: 'address', }, { name: 'amount', type: 'uint256', }, ], }) const formatted = AbiError.format(exampleError) expect(formatted).toMatchInlineSnapshot( `"error Example(address spender, uint256 amount)"`, ) }) }) describe('from', () => { test('default', () => { { const abiItem = AbiError.from({ inputs: [{ name: 'v', type: 'uint8' }], name: 'BadSignatureV', type: 'error', }) expect(abiItem).toMatchInlineSnapshot(` { "hash": "0x1f003d0ab3c21a082e88d5c936eb366321476aa1508b9238066e9f135aa38772", "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) } { const abiItem = AbiError.from('error BadSignatureV(uint8 v)') expect(abiItem).toMatchInlineSnapshot(` { "hash": "0x1f003d0ab3c21a082e88d5c936eb366321476aa1508b9238066e9f135aa38772", "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) } { const abiItem = AbiError.from([ 'struct Signature { uint8 v; }', 'error BadSignatureV(Signature signature)', ]) expect(abiItem).toMatchInlineSnapshot(` { "hash": "0xfced1c858d7f2bfb0878dcc1cb75305474698643ad13e7d8e5e1b96283a8c7c2", "inputs": [ { "components": [ { "name": "v", "type": "uint8", }, ], "name": "signature", "type": "tuple", }, ], "name": "BadSignatureV", "type": "error", } `) } }) test('options: prepare', () => { const abiItem = AbiError.from( { inputs: [{ name: 'v', type: 'uint8' }], name: 'BadSignatureV', type: 'error', }, { prepare: false }, ) expect(abiItem).toMatchInlineSnapshot(` { "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) }) }) describe('fromAbi', () => { test('default', () => { expect(AbiError.fromAbi(seaportContractConfig.abi, 'BadSignatureV')) .toMatchInlineSnapshot(` { "hash": "0x1f003d0ab3c21a082e88d5c936eb366321476aa1508b9238066e9f135aa38772", "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) }) test('behavior: prepare = false', () => { expect( AbiError.fromAbi(seaportContractConfig.abi, 'BadSignatureV', { prepare: false, }), ).toMatchInlineSnapshot(` { "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) }) test('behavior: selector as name', () => { const item = AbiError.fromAbi(seaportContractConfig.abi, 'BadSignatureV') const selector = AbiItem.getSelector(item) expect(AbiError.fromAbi(seaportContractConfig.abi, selector)) .toMatchInlineSnapshot(` { "hash": "0x1f003d0ab3c21a082e88d5c936eb366321476aa1508b9238066e9f135aa38772", "inputs": [ { "name": "v", "type": "uint8", }, ], "name": "BadSignatureV", "type": "error", } `) }) test('behavior: able to extract solidity Error', () => { const abi = Abi.from(['error Bar()', 'error Foo()', 'error Foo(uint256)']) const item = AbiError.fromAbi(abi, 'Error') expect(item).toMatchInlineSnapshot(` { "hash": "0x08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa", "inputs": [ { "name": "message", "type": "string", }, ], "name": "Error", "type": "error", } `) }) test('behavior: able to extract solidity Error (selector)', () => { const abi = Abi.from(['error Bar()', 'error Foo()', 'error Foo(uint256)']) const item = AbiError.fromAbi(abi, AbiError.solidityErrorSelector) expect(item).toMatchInlineSnapshot(` { "hash": "0x08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa", "inputs": [ { "name": "message", "type": "string", }, ], "name": "Error", "type": "error", } `) }) test('behavior: able to extract solidity Panic', () => { const abi = Abi.from(['error Bar()', 'error Foo()', 'error Foo(uint256)']) const item = AbiError.fromAbi(abi, 'Panic') expect(item).toMatchInlineSnapshot(` { "hash": "0x25fba4f52ccf6f699393995e0f649c9072d088cffa43609495ffad9216c5b1dc", "inputs": [ { "name": "reason", "type": "uint8", }, ], "name": "Panic", "type": "error", } `) }) test('behavior: able to extract solidity Panic (selector)', () => { const abi = Abi.from(['error Bar()', 'error Foo()', 'error Foo(uint256)']) const item = AbiError.fromAbi(abi, AbiError.solidityPanicSelector) expect(item).toMatchInlineSnapshot(` { "hash": "0x25fba4f52ccf6f699393995e0f649c9072d088cffa43609495ffad9216c5b1dc", "inputs": [ { "name": "reason", "type": "uint8", }, ], "name": "Panic", "type": "error", } `) }) test('error: no matching name', () => { expect(() => // @ts-expect-error AbiError.fromAbi(seaportContractConfig.abi, 'cancel'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI error with name "cancel" not found.]`, ) }) test('error: no matching name', () => { expect(() => AbiError.fromAbi([] as readonly unknown[], 'balanceOf', { args: ['0x0000000000000000000000000000000000000000'], }), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "balanceOf" not found.]`, ) }) test('error: no matching data', () => { expect(() => AbiError.fromAbi([], '0xdeadbeef'), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "0xdeadbeef" not found.]`, ) }) test('behavior: overloads', () => { const abi = Abi.from([ 'error Bar()', 'error Foo(bytes)', 'error Foo(uint256)', ]) const item = AbiError.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xefc9afd358f1472682cf8cc82e1d3ae36be2538ed858a4a604119399d6f22b48", "inputs": [ { "type": "bytes", }, ], "name": "Foo", "overloads": [ { "inputs": [ { "type": "uint256", }, ], "name": "Foo", "type": "error", }, ], "type": "error", } `) }) test('behavior: overloads: no inputs', () => { const abi = Abi.from(['error Bar()', 'error Foo()', 'error Foo(uint256)']) const item = AbiError.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xbfb4ebcfff8f360b39de1de85df1edc256d63337b743120bf6e2e2144b973d38", "inputs": [], "name": "Foo", "type": "error", } `) }) test('overloads: no args', () => { const abi = Abi.from(['error Bar()', 'error Foo(uint256)', 'error Foo()']) const item = AbiError.fromAbi(abi, 'Foo') expect(item).toMatchInlineSnapshot(` { "hash": "0xbfb4ebcfff8f360b39de1de85df1edc256d63337b743120bf6e2e2144b973d38", "inputs": [], "name": "Foo", "type": "error", } `) }) test('behavior: overloads: different types', () => { const abi = Abi.from([ 'error Mint()', 'error Mint(uint256)', 'error Mint(string)', ]) const item = AbiError.fromAbi(abi, 'Mint') expect(item).toMatchInlineSnapshot(` { "hash": "0x34c73884fbbb790762253ae313e57da96c00670344647f0cb8d41ee92b9f1971", "inputs": [], "name": "Mint", "type": "error", } `) const item_2 = AbiError.fromAbi(abi, 'Mint', { args: [420n], }) expect(item_2).toMatchInlineSnapshot(` { "hash": "0x07883703ed0e86588a40d76551c92f8a4b329e3bf19765e0e6749473c1a84665", "inputs": [ { "type": "uint256", }, ], "name": "Mint", "type": "error", } `) const item_3 = AbiError.fromAbi(abi, 'Mint', { args: ['foo'], }) expect(item_3).toMatchInlineSnapshot(` { "hash": "0xc5e1d731c47dbd6a8c38e6ee9137792904eae9d20174034d1dc9a5781a0f855b", "inputs": [ { "type": "string", }, ], "name": "Mint", "type": "error", } `) }) test('behavior: overloads: tuple', () => { const abi = Abi.from([ 'error Example(uint256 foo, (string a, string b, uint256 c) bar)', 'error Example(uint256 foo, (string a, (string merp, string meep) b, address c) bar)', ]) const item = AbiError.fromAbi(abi, 'Example', { args: [ 420n, { a: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', b: { merp: 'test', meep: 'test' }, c: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', }, ], }) expect(item).toMatchInlineSnapshot(` { "hash": "0x3cfe2f5f5794a704453504eac86b65a35f5912de763230232d0d593c5127e517", "inputs": [ { "name": "foo", "type": "uint256", }, { "components": [ { "name": "a", "type": "string", }, { "components": [ { "name": "merp", "type": "string", }, { "name": "meep", "type": "string", }, ], "name": "b", "type": "tuple", }, { "name": "c", "type": "address", }, ], "name": "bar", "type": "tuple", }, ], "name": "Example", "type": "error", } `) }) test('behavior: overloads: ambiguious types', () => { expect(() => AbiError.fromAbi( Abi.from(['error Foo(address)', 'error 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(() => AbiError.fromAbi( Abi.from([ 'error Foo(string)', 'error Foo(uint)', 'error 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( AbiError.fromAbi( Abi.from([ 'error Foo(string)', 'error Foo(uint)', 'error Foo(address)', ]), 'Foo', { // 21 bytes (invalid address) args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251eee'], }, ), ).toMatchInlineSnapshot(` { "hash": "0x9f0b7f1630bdb7d474466e2dfef0fb9dff65f7a50eec83935b68f77d0808f08a", "inputs": [ { "type": "string", }, ], "name": "Foo", "type": "error", } `) expect( AbiError.fromAbi( Abi.from([ 'error Foo(string)', 'error Foo(uint)', 'error Foo(address)', ]), 'Foo', { // non-hex (invalid address) args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251z'], }, ), ).toMatchInlineSnapshot(` { "hash": "0x9f0b7f1630bdb7d474466e2dfef0fb9dff65f7a50eec83935b68f77d0808f08a", "inputs": [ { "type": "string", }, ], "name": "Foo", "type": "error", } `) expect(() => AbiError.fromAbi( Abi.from([ 'error Foo(address)', 'error Foo(uint)', 'error 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.] `) expect(() => AbiError.fromAbi( Abi.from(['error Foo((address))', 'error 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(() => AbiError.fromAbi( Abi.from([ 'error Foo(string, (address))', 'error Foo(string, (bytes))', ]), 'Foo', { args: ['foo', ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e']], }, ), ).toThrowErrorMatchingInlineSnapshot(` [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items. \`bytes\` in \`Foo(string,(bytes))\`, and \`address\` in \`Foo(string,(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(AbiError.getSelector('error BadSignatureV(uint8 v)')).toEqual( '0x1f003d0a', ) expect(AbiError.getSelector('BadSignatureV(uint8 v)')).toEqual('0x1f003d0a') }) test('behavior: from `AbiError`', () => { expect( AbiError.getSelector(AbiError.from('error BadSignatureV(uint8 v)')), ).toEqual('0x1f003d0a') }) }) test('exports', () => { expect(Object.keys(AbiError)).toMatchInlineSnapshot(` [ "decode", "extract", "encode", "format", "from", "fromAbi", "getSelector", "panicReasons", "solidityError", "solidityErrorSelector", "solidityPanic", "solidityPanicSelector", ] `) })