Skip to content

Decode revert data against the ABI: custom errors, Error(string), and Panic(uint256) #122

Description

@koko1123

Motivation

Provider now captures the raw revert payload -- RpcErrorInfo carries the JSON-RPC code and the error.data hex (truncated to 512 bytes) -- but the caller still gets a hex string. Every modern Solidity contract reverts with a custom error (error InsufficientBalance(uint256 available, uint256 required)), so "why did my call fail" is currently answered with 0x556f1830... and a manual trip to a 4-byte database.

The two halves needed to close this are both already in the tree and simply not wired together: abi_json.zig parses "type": "error" entries into abi_types.AbiError, and abi_types.selectorFromSignature computes the 4-byte selector. This is a small, high-visibility quality-of-life win and a good first issue.

Scope

  • decodeRevert(allocator, revert_data, abi) !DecodedRevert in a new src/revert.zig (or alongside abi_decode), matching revert_data[0..4] against the selector of each AbiError in the parsed ABI and decoding the remainder with the existing abi_decode machinery
  • Handle the three standard shapes before any custom error:
    • Error(string) -- selector 0x08c379a0, the classic require(cond, "message")
    • Panic(uint256) -- selector 0x4e487b71, with the panic codes mapped to names (0x01 assert, 0x11 arithmetic overflow, 0x12 division by zero, 0x32 array out of bounds, and the rest)
    • empty revert data -- a bare revert() or an out-of-gas, which must be reported as "no reason given" rather than as a decode failure
  • DecodedRevert as a tagged union over { string_error, panic, custom, unknown }, where unknown preserves the raw bytes and the unmatched selector so the caller can still log something useful
  • A comptime twin on the abigen bindings: Contract.decodeRevert(revert_data) resolving against that contract's own errors, matching how decodeEvent already works there
  • Note the 512-byte truncation in RpcErrorInfo: a revert carrying a long string or a dynamic array can be cut off. Either raise the cap for the decode path or return a clearly-flagged partial decode -- silently decoding truncated data into wrong values would be worse than not decoding at all.

Testing

Entirely offline. Encode known reverts by hand and assert the round trip: a require string, each panic code, a custom error with static params, a custom error with a dynamic param, an unknown selector, and empty data. abi_json.zig already has an InsufficientBalance error fixture in its tests to build on.

Pointers

src/provider.zig (the RpcErrorInfo capture path and its truncation comment near line 42), src/abi_json.zig:53 (error-entry parsing) and src/abi_types.zig:307 (AbiError), src/abi_types.zig:316 (selectorFromSignature), src/abi_decode.zig for the parameter decoding, and src/abigen.zig:329 (decodeEvent) as the template for the comptime binding.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions