Skip to content

Sign destination-phase EVM transactions exactly once - #1303

Merged
ebma merged 1 commit into
stagingfrom
claude/fix-evm-destination-double-signing
Aug 3, 2026
Merged

Sign destination-phase EVM transactions exactly once#1303
ebma merged 1 commit into
stagingfrom
claude/fix-evm-destination-double-signing

Conversation

@ebma

@ebma ebma commented Aug 3, 2026

Copy link
Copy Markdown
Member

Note

This branch now includes #1302 (both PRs add signUnsigned.test.ts, so they are stacked to avoid an add/add conflict). Merge #1302 first — this diff then collapses to just the grouping change.

Summary

Since 5515a7a ("adjust morpho flow from non-base networks") expanded the direct EVM signing group to Arbitrum, Avalanche, BSC, and Ethereum, destination-phase transactions (destinationTransfer, backupSquidRouterApprove, backupSquidRouterSwap, backupApprove) on those networks matched both signing groups in signUnsignedTransactions and were signed and returned twice. The alreadySigned guard could never catch this: it compares the unsigned txData object against the already-replaced signed hex string, so it never matches anything.

Impact: duplicate identical presigned entries in ramp state for onramps to those networks (API validation tolerates them — subset matching, no exact counts), violating the one-signature-per-transaction model. No fund-loss path identified.

Changes

  • The seven directly-signed EVM networks live in one list; grouping moved to an exported pure groupUnsignedTxsForSigning, whose destination group excludes exactly that list — the groups are disjoint by construction and can't drift apart again.
  • Removed the dead alreadySigned guard.
  • Regression tests: an Arbitrum destinationTransfer lands only in the EVM group; non-listed networks stay in the destination group; a property test sweeps every network × destination phase asserting no tx lands in both groups. Verified 2/3 fail against the old filter. Tested via the pure grouping function because viem's signTransaction always fetches eth_chainId, so the real signing path would hit live RPCs.

Known pre-existing quirk, deliberately untouched: a destination-phase tx on Moonbeam would still match both the Moonbeam group and the destination group — that overlap predates 5515a7a; whether Moonbeam can be a ramp destination for these phases needs a product-level answer before changing it.

Spec check: docs/security-spec/03-ramp-engine/transaction-validation.md documents presigned verification, not client-side grouping; this restores documented behavior, so no spec change.

Test

  • bun test in packages/shared (89 pass)
  • bun lint, tsc --noEmit, bun build:shared

Since the morpho flow expanded the direct EVM signing group to
Arbitrum, Avalanche, BSC and Ethereum, destination-phase transactions
on those networks matched both signing groups and were signed and
returned twice; the alreadySigned guard could never match because
signing replaces txData before comparison. Derive both groups from one
network list so they stay disjoint, and drop the dead guard.
@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 9dbc354
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6a7061ded39ec1000841e437
😎 Deploy Preview https://deploy-preview-1303--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for vrtx-dashboard ready!

Name Link
🔨 Latest commit 9dbc354
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6a7061decc206b0008eb9639
😎 Deploy Preview https://deploy-preview-1303--vrtx-dashboard.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit 9dbc354
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6a7061deb71cd50008ea68d6
😎 Deploy Preview https://deploy-preview-1303--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents duplicate signing of destination-phase transactions on directly signed EVM networks.

Changes:

  • Centralizes directly signed EVM networks and transaction grouping.
  • Removes the ineffective duplicate guard.
  • Adds regression and cross-network grouping tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/shared/src/helpers/signUnsigned.ts Makes EVM and destination signing groups disjoint.
packages/shared/src/helpers/signUnsigned.test.ts Tests destination-phase grouping and overlap prevention.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ebma
ebma merged commit 80c6d26 into staging Aug 3, 2026
7 checks passed
@ebma
ebma deleted the claude/fix-evm-destination-double-signing branch August 3, 2026 09:48
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.

2 participants