Skip to content

Commit

Permalink
feat: add raw property to ContractFunctionRevertedError (#3258)
Browse files Browse the repository at this point in the history
* Add raw revert data to ContractFunctionRevertedError

Exposes otherwise missing raw revert data via a new rawData field
on the ContractFunctionRevertedError

Fixes #3235

* Update contract.ts

* Update contract.ts

* Update contract.test.ts

* Update two-crabs-push.md

* Update two-crabs-push.md

---------

Co-authored-by: jxom <7336481+jxom@users.noreply.github.com>
  • Loading branch information
will-af and jxom authored Jan 23, 2025
1 parent 5fb0e52 commit f32fc92
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/two-crabs-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added `raw` property to `ContractFunctionRevertedError` for raw revert data.
104 changes: 61 additions & 43 deletions src/errors/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,98 +317,116 @@ describe('ContractFunctionExecutionError', () => {

describe('ContractFunctionRevertedError', () => {
test('default', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
message: 'oh no',
functionName: 'totalSupply',
}),
).toMatchInlineSnapshot(`
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
message: 'oh no',
functionName: 'totalSupply',
})

expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
oh no
Version: viem@x.y.z]
`)

expect(err.rawData).be.undefined
})

test('data: Error(string)', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000022456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473000000000000000000000000000000000000000000000000000000000000',
functionName: 'totalSupply',
}),
).toMatchInlineSnapshot(`
const data =
'0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000022456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473000000000000000000000000000000000000000000000000000000000000'
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data,
functionName: 'totalSupply',
})
expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
EnumerableSet: index out of bounds
Version: viem@x.y.z]
`)

expect(err.rawData).toEqual(data)
})

test('data: Panic(uint256)', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data: '0x4e487b710000000000000000000000000000000000000000000000000000000000000001',
functionName: 'totalSupply',
}),
).toMatchInlineSnapshot(`
const data =
'0x4e487b710000000000000000000000000000000000000000000000000000000000000001'
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data,
functionName: 'totalSupply',
})
expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
An \`assert\` condition failed.
Version: viem@x.y.z]
`)

expect(err.rawData).toEqual(data)
})

test('data: custom error', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data: '0xdb731cf4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000066275676765720000000000000000000000000000000000000000000000000000',
functionName: 'customComplexError',
}),
).toMatchInlineSnapshot(`
const data =
'0xdb731cf4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000066275676765720000000000000000000000000000000000000000000000000000'
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data,
functionName: 'customComplexError',
})
expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "customComplexError" reverted.
Error: ComplexError((address sender, uint256 bar), string message, uint256 number)
({"sender":"0x0000000000000000000000000000000000000000","bar":"69"}, bugger, 69)
Version: viem@x.y.z]
`)

expect(err.rawData).toEqual(data)
})

test('data: zero data', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data: '0x',
functionName: 'customComplexError',
}),
).toMatchInlineSnapshot(`
const data = '0x'
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data,
functionName: 'customComplexError',
})
expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "customComplexError" reverted.
Version: viem@x.y.z]
`)

expect(err.rawData).toEqual(data)
})

test('data: error signature does not exist on ABI', () => {
expect(
new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data: '0xdb731cfa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000066275676765720000000000000000000000000000000000000000000000000000',
functionName: 'totalSupply',
}),
).toMatchInlineSnapshot(`
const data =
'0xdb731cfa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000066275676765720000000000000000000000000000000000000000000000000000'
const err = new ContractFunctionRevertedError({
abi: ErrorsExample.abi,
data,
functionName: 'totalSupply',
})
expect(err).toMatchInlineSnapshot(`
[ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following signature:
0xdb731cfa
Unable to decode signature "0xdb731cfa" as it was not found on the provided ABI.
Make sure you are using the correct ABI and that the error exists on it.
You can look up the decoded signature here: https://openchain.xyz/signatures?query=0xdb731cfa.
Revert data: "${data}"
Docs: https://viem.sh/docs/contract/decodeErrorResult
Version: viem@x.y.z]
`)

expect(err.rawData).toEqual(data)
})
})
4 changes: 4 additions & 0 deletions src/errors/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export type ContractFunctionRevertedErrorType =
}
export class ContractFunctionRevertedError extends BaseError {
data?: DecodeErrorResultReturnType | undefined
raw?: Hex | undefined
reason?: string | undefined
signature?: Hex | undefined

Expand Down Expand Up @@ -232,6 +233,8 @@ export class ContractFunctionRevertedError extends BaseError {
`Unable to decode signature "${signature}" as it was not found on the provided ABI.`,
'Make sure you are using the correct ABI and that the error exists on it.',
`You can look up the decoded signature here: https://openchain.xyz/signatures?query=${signature}.`,
'',
`Revert data: "${data}"`,
]
}

Expand All @@ -252,6 +255,7 @@ export class ContractFunctionRevertedError extends BaseError {
)

this.data = decodedData
this.raw = data
this.reason = reason
this.signature = signature
}
Expand Down

0 comments on commit f32fc92

Please sign in to comment.