From f32fc924cad24d4aace31f9d41f1a020e3cf11d9 Mon Sep 17 00:00:00 2001 From: will-af <130376900+will-af@users.noreply.github.com> Date: Wed, 22 Jan 2025 18:11:39 -0600 Subject: [PATCH] feat: add `raw` property to `ContractFunctionRevertedError` (#3258) * 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> --- .changeset/two-crabs-push.md | 5 ++ src/errors/contract.test.ts | 104 ++++++++++++++++++++--------------- src/errors/contract.ts | 4 ++ 3 files changed, 70 insertions(+), 43 deletions(-) create mode 100644 .changeset/two-crabs-push.md diff --git a/.changeset/two-crabs-push.md b/.changeset/two-crabs-push.md new file mode 100644 index 0000000000..00da3513d0 --- /dev/null +++ b/.changeset/two-crabs-push.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Added `raw` property to `ContractFunctionRevertedError` for raw revert data. diff --git a/src/errors/contract.test.ts b/src/errors/contract.test.ts index bab6a47457..88211e7907 100644 --- a/src/errors/contract.test.ts +++ b/src/errors/contract.test.ts @@ -317,58 +317,67 @@ 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) @@ -376,39 +385,48 @@ describe('ContractFunctionRevertedError', () => { 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) }) }) diff --git a/src/errors/contract.ts b/src/errors/contract.ts index 9ab413ffb1..0940701328 100644 --- a/src/errors/contract.ts +++ b/src/errors/contract.ts @@ -170,6 +170,7 @@ export type ContractFunctionRevertedErrorType = } export class ContractFunctionRevertedError extends BaseError { data?: DecodeErrorResultReturnType | undefined + raw?: Hex | undefined reason?: string | undefined signature?: Hex | undefined @@ -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}"`, ] } @@ -252,6 +255,7 @@ export class ContractFunctionRevertedError extends BaseError { ) this.data = decodedData + this.raw = data this.reason = reason this.signature = signature }