Skip to content

fix: F-2026-18826 | [Dual Defense] Receipt RPC Error Treated as Not-Found Can Remint After Destination Already Paid - #313

Merged
Aman035 merged 1 commit into
audit-fixesfrom
F-2026-18826
Aug 19, 2026
Merged

fix: F-2026-18826 | [Dual Defense] Receipt RPC Error Treated as Not-Found Can Remint After Destination Already Paid#313
Aman035 merged 1 commit into
audit-fixesfrom
F-2026-18826

Conversation

@Aman035

@Aman035 Aman035 commented Aug 19, 2026

Copy link
Copy Markdown
Member

F-2026-18826 Receipt RPC error treated as not-found

Issue

  • VerifyBroadcastedTx returned found=false, err=nil on any receipt RPC error, so a transient failure was indistinguishable from "the tx is not there".
  • With a consumed nonce the resolver reads that as "never executed" and votes failure against an outbound the destination already paid.
  • The resolver's retry-on-error path was already coded and already tested — against a mock returning errors the real builder could never produce.

Approach taken

  • EVM: propagate the RPC error, keep receipt == nil as a verdict. The RPC client already returned (nil, nil) for not-found and (nil, err) for failures, so the distinction only had to stop being discarded a layer up.
  • SVM had the same defect, needing the inverse treatment: solana-go reports an absent tx as ErrNotFound, so that maps to a verdict and everything else propagates. Propagating uniformly would turn every missing tx into an unbounded retry.
  • Documented the error contract on the TxBuilder interface. Its absence is why the implementations drifted from the resolver's expectation.
  • Broadcaster unaffected: on vErr != nil it already fell through to checkNonceAndMarkBroadcasted.

Tests

  • Both builders driven against a local JSON-RPC server, not a mock — a mock is what hid this. RPC errors surface; null receipt and ErrNotFound stay verdicts.
  • Regression: receipt error plus consumed nonce must not fail-vote. Asserts the nonce is never consulted, then that a later success receipt resolves to COMPLETED.
  • Mutation checked: restoring the collapse fails the EVM tests, disabling the ErrNotFound branch fails the SVM test.

Out of scope

Ballot keying on Success and the remint via handleFailedOutbound are in x/uexecutor.

@Aman035
Aman035 merged commit f176bfa into audit-fixes Aug 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant