feat: bridge --asset eth — ETH rails via Wormhole (in + out) - #28
Merged
Conversation
One knob on the existing engines (asset-parameterized, not duplicated): --asset usdc (default, CCTP, unchanged) | eth (Wormhole). In: wrap on the source -> the sponsor completes on Solana -> lands as wETH (never gas; no settle EIP-712). Out: approve+burn wETH on Rome via RomeBridgeWithdraw -> the USER claims on Ethereum only (rail-aware claim handle carries the isTransferCompleted gotcha). Guards fire pre-key/network: unknown asset, eth-with-intent, eth --to must be the Ethereum rail. Also fixes a real activate gap the funded gate caught: a previously- activated PDA drained below the burn reserve made activate() revert AlreadyActivated — runActivate now has three states (skip / activate / topUpUserPda at the on-chain rate), funded-proven (refill to exactly USER_PDA_FUNDING for ~1.03 USDC). Funded round trip on Hadrian: ETH-in 0.002 (wrap 0xb01fe618 -> VAA -> wETH 200000@8dp landed) -> activate top-up 0xe4aaf88d -> ETH-out burn 0x730db82a SUCCESS, claim ready, wETH back to 0. 122 unit tests; docs (GUIDES ETH in/out + ARCHITECTURE rows).
skansal-rome
added a commit
that referenced
this pull request
Jul 24, 2026
Pins the released surface to main. Since v0.9.0: bridge --asset eth (#28) — ETH via Wormhole, in (Sepolia -> wETH) + out (wETH -> Ethereum only), funded round-trip validated on Hadrian, plus the activate three-state fix (drained-PDA top-up); AGENTS.md v3.2 (#29); README refresh (#30). Bumps package.json/lock and the README install pin 0.9.0 -> 0.10.0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes the bridge surface for ETH holders — the last missing rail of the from-home on-ramp.
What it adds
One knob on the existing verbs:
--asset usdc|eth(defaultusdc— zero behavior change).rome bridge <chain> --from sepolia --amount 0.002 --asset eth: wrap+transfer on the source (one user tx) → Wormhole VAA → Rome's sponsor completes on Solana → lands as wETH. Never gas (gas is USDC), so--intentis rejected for ETH; no settle EIP-712.rome bridge <chain> --to sepolia --amount 0.002 --asset eth: approve+burn wETH on Rome (RomeBridgeWithdraw) → you claim on Ethereum only (the Wormhole route has no destination knob; the CLI refuses any other--to). The claim handle is rail-aware and carries theisTransferCompletedgotcha (re-redeeming an already-completed VAA reverts with a misleading gas error).Bonus fix the funded gate caught:
activatethree-stateA previously-activated account whose PDA drained below the burn reserve (each burn consumes rent) made
activate()revertAlreadyActivated.runActivatenow handles all three states: skip (≥ reserve) / first-timeactivate(0) /topUpUserPdaat the on-chain rate (drained). Funded-proven live: refill to exactlyUSER_PDA_FUNDING(29,969,440 lamports) for ~1.03 USDC (0xe4aaf88d…).Validation — funded ETH round trip on Hadrian
0xb01fe618…(Sepolia) → VAA → wETH 200000 (8dp) landed (balance 0 → 200000)0xe4aaf88d…(drained-state path)0x730db82a…SUCCESS (block 478350002) → claimready→ wETH back to 0 — full round tripuserSigns-less step-1 tx via the real SDK helper, WH-out no-dest builder + claim detection, 3 pre-network guards, drained-state top-up) · typecheck/build/MCP smoke clean · both directions live-dry-run through the CLI · leak-scan cleanDocs
GUIDES: ETH-in blurb + ETH-out rules (Ethereum-only, claims-are-yours, VAA gotcha) · ARCHITECTURE: both bridge rows asset-aware.
Feature PR, no version bump — next tag pins it.