fix: decode authorization util and prefix errors#8656
Conversation
fa2e557 to
26b8e0d
Compare
26b8e0d to
dfe2b38
Compare
dfe2b38 to
71a8388
Compare
… EIP-7702 authorization signatures and add layered submission error prefixes Centralizes EIP-7702 authorization signature decoding in the transaction controller via a new `decodeAuthorizationSignature` utility that returns `r`, `s`, and `yParity` in RLP-canonical form (no leading zero nibbles, `0x0` for zero). go-ethereum-style decoders (Sentinel relay, public RPCs, Relay quote endpoints) reject non-canonical integers at decode time, surfacing as bare `failed to decode param in array[0] invalid JSON input` errors in production metrics. With canonical decoding centralised here, clients consume signed authorization tuples directly without needing their own per-field strip helpers. Adds layered submission error prefixes that cascade up the call stack to attribute every failure surface in error-tracking metrics: - `RPC submit: <reason>` on `eth_sendRawTransaction` failures - `Relay submit: <reason>` wraps every error from `submitRelayQuotes` - `Relay execute: <reason>` wraps Relay `/execute` POST failures (cascades inside `Relay submit:` to distinguish the gasless-execute path from the non-execute deposit path) - `MetaMask Pay: <reason>` wraps every error from the Pay publish hook, cascading any inner prefixes Example cascades surfaced in metrics: - `MetaMask Pay: Relay submit: Relay execute: Insufficient liquidity` - `MetaMask Pay: Relay submit: RPC submit: nonce too low` - `MetaMask Pay: Insufficient source token balance for relay deposit` Also adds a private `relayFetch` helper in `relay-api.ts` that surfaces the Relay server's `message` or `error` response field (or status code) on non-OK responses, replacing the previous URL-leaking generic `Fetch failed with status '500' for request 'https://api.relay.link/...'` message.
71a8388 to
1eb9b8c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1eb9b8c. Configure here.
|
|
||
| successfulFetchMock | ||
| .mockResolvedValueOnce({ | ||
| ok: true, |
There was a problem hiding this comment.
Test mock missing ok: true in timeout scenario
Medium Severity
The .mockImplementation response object is missing ok: true. Since getRelayStatus now goes through relayFetch, which checks response.ok, this causes the second poll to throw a relayFetch error (with message "undefined") rather than returning a successful { status: 'pending' } response. The test still passes by accident — the polling loop catches the throw as a network error, and the timeout fires using lastStatus from the first poll — but it no longer verifies the intended behavior of timing out after receiving repeated valid pending responses.
Reviewed by Cursor Bugbot for commit 1eb9b8c. Configure here.


Explanation
Current
EIP-7702 production failures across mobile and extension are surfacing as bare, unattributable strings in our error metrics — most prominently
failed to decode param in array[0] invalid JSON inputfrom Sentinel relay.signAuthorizationslices raw 32-byte signature halves intorandswithout canonicalizing.eth_sendRawTransaction, the Relay strategy's/executePOST, the non-execute relay deposit path, or the Pay publish hook. Metrics can't distinguish them, and Relay's actual server error ({ message: "Insufficient liquidity" }) is discarded bysuccessfulFetchin favour of a generic URL-leaking template.Solution
Canonicalize once, in core. A new exported
decodeAuthorizationSignature(signature)utility in@metamask/transaction-controllerdecodes a 65-byte EIP-7702 authorization signature into RLP-canonicalr,s, andyParity.signAuthorizationListis refactored to use it, so every signed authorization tuple emitted by the controller is canonical out of the box. Mobile/extension can read straight offtxMeta.txParams.authorizationListand submit to any backend without their own strip helpers.Layered submission error prefixes. Four prefixes, each applied at the lowest sensible layer, that cascade up the call stack to attribute every failure surface in metrics:
RPC submit:eth_sendRawTransactionfailuresRelay submit:submitRelayQuotesbodyRelay execute:/executePOST failures (cascades insideRelay submit:)MetaMask Pay:TransactionPayPublishHook.#hookWrapperA private
relayFetchhelper inrelay-api.tsreplacessuccessfulFetchfor Relay endpoints. On non-OK responses it surfaces the response body'smessageorerrorfield as<status> - <message>, falling back to<status>alone — no URL leakage, server's actual reason preserved when present.Example errors as they appear in metrics
References
Checklist
Note
Medium Risk
Changes transaction submission error handling and EIP-7702 signature decoding, which can affect downstream clients’ ability to submit transactions and how failures are reported. Main risk is altered error strings/prefixes and canonicalization behavior impacting integrations/tests.
Overview
Adds a new exported
decodeAuthorizationSignaturehelper for EIP-7702 that canonicalizesr/s(strips leading zeroes, uses0x0for zero) and derivesyParity, and refactors authorization signing to use it.Standardizes failure-surface attribution by wrapping submission errors with layered prefixes:
RPC submit:foreth_sendRawTransactionfailures (including nesteddata.message),Relay submit:for Relay strategy execution,Relay execute:for Relay/executePOST failures, andMetaMask Pay:for Pay publish hook failures.Replaces Relay’s
successfulFetchusage with a localrelayFetchthat preserves server-provided non-OK details (<status> - <message|error>or<status>) without leaking request URLs, and updates tests/changelogs accordingly.Reviewed by Cursor Bugbot for commit 1eb9b8c. Bugbot is set up for automated code reviews on this repo. Configure here.