ox
Version:
Ethereum Standard Library
1,145 lines (1,051 loc) • 31.2 kB
text/typescript
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",
]
`)
})