Skip to content

deploy Universal Router 2.1 to Robinhood Chain#141

Closed
david-uniswap wants to merge 2 commits into
david-nick/robinhood-chainfrom
david-nick/robinhood-ur-2.1
Closed

deploy Universal Router 2.1 to Robinhood Chain#141
david-uniswap wants to merge 2 commits into
david-nick/robinhood-chainfrom
david-nick/robinhood-ur-2.1

Conversation

@david-uniswap

Copy link
Copy Markdown
Collaborator

Summary

Deploys UniversalRouter v2.1 to Robinhood Chain (4663). Replaces the prior v2.0 PR (closing in favor of this).

  • UniversalRouter (v2.1): 0x248a454ac3584c2a48d1fcb28d3910a6b6ea00af
    • Tx: 0x66347de408f4f8f5de452b1f3b709c4ec4313c77ce75d69fea9924526004c8e3
  • UnsupportedProtocol (acrossSpokePool placeholder): 0x7332D11BD10d18A04B119Cd4671a96f3148002c4
    • Tx: 0x029d23d957e6d9f39b2bd655a10d01e764999b32344c2ccdcb9667259cd80f24

Why v2.1 over v2.0

v2.1 includes features that have nothing to do with Across:

  • Proxy approval swapping via SwapProxy (no Permit2 signed messages required)
  • PAY_PORTION_FULL_PRECISION (command 0x07) for high-precision fees
  • Per-hop slippage via minHopPriceX36 on v3SwapExactInput/Output
  • Expanded command space (mask 0x3f → 0x7f)

The spokePool constructor arg is only consumed by command 0x40 (ACROSS_V4_DEPOSIT_V3). Pointing it at our deployed UnsupportedProtocol means any Across call reverts cleanly with UnsupportedProtocolError() instead of the empty extcodesize revert that address(0) produces — same pattern Uniswap uses elsewhere for missing protocols on a given chain.

When/if Across adds a SpokePool on Robinhood, we can redeploy UR pointing at the real SpokePool.

Two-step deploy

Deploy-all.s.sol reads acrossSpokePool.value directly from the task config and doesn't propagate UnsupportedProtocol's deployed address, so the deploy ran in two passes:

  1. Step A — task config with only unsupported-protocol enabled. Deployed UnsupportedProtocol.
  2. Step B — task config updated: UnsupportedProtocol marked deploy: false + address, acrossSpokePool.value set to its address, universal-router flipped to deploy: true. Deployed UniversalRouter.

Constructor args (RouterParameters struct)

field value
permit2 0x000000000022D473030F116dDEE9F6B43aC78BA3
weth9 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
v2Factory 0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f
v3Factory 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
v2PairInitCodeHash 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f
v3PoolInitCodeHash 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
v4PoolManager 0x8366a39CC670B4001A1121B8F6A443A643e40951
v3NFTPositionManager 0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3
v4PositionManager 0x58daec3116aae6D93017bAAea7749052E8a04fA7
spokePool 0x7332D11BD10d18A04B119Cd4671a96f3148002c4 (UnsupportedProtocol)

Verification

Onchain immutables match expected wiring:

  • SPOKE_POOL() → UnsupportedProtocol ✓
  • V3_POSITION_MANAGER() → v3 NPM ✓
  • V4_POSITION_MANAGER() → v4 PM ✓
  • poolManager() → v4 PoolManager ✓
  • permit2, v2Factory, v3Factory, weth, init code hashes confirmed embedded in initcode payload ✓

Chronicles patching

UR v2.1 uses CREATE2 via the canonical 0x4e59…956c deployer, which leaves contractName=null in the broadcast file and causes forge-chronicles to skip it (can't disambiguate between v2.0 and v2.1 artifacts). The v2.0 deployer used plain CREATE so the previous chronicles run worked automatically. For v2.1, the entries in deployments/json/4663.json were patched in manually (see commit body).

Cost

step gas ETH
UnsupportedProtocol 67,246 0.0000067
UniversalRouter v2.1 4,922,563 0.000492
total 4,989,809 ~0.000499

Test plan

  • Run V2/V3/V4 smoke tests against the new UR v2.1 address (simulation + onchain)
  • Verify UnsupportedProtocol + UR v2.1 on Blockscout (deferred to follow-up commit)

Adds UniversalRouter v2.1 to the Robinhood Chain (4663) deployment, with
UnsupportedProtocol as the acrossSpokePool placeholder.

Deployed:
- UniversalRouter (v2.1): 0x248a454ac3584c2a48d1fcb28d3910a6b6ea00af
  Tx:                     0x66347de408f4f8f5de452b1f3b709c4ec4313c77ce75d69fea9924526004c8e3
- UnsupportedProtocol:    0x7332D11BD10d18A04B119Cd4671a96f3148002c4
  Tx:                     0x029d23d957e6d9f39b2bd655a10d01e764999b32344c2ccdcb9667259cd80f24

Why v2.1 over v2.0: v2.1 includes features that have nothing to do with
Across (proxy approval swapping via SwapProxy, PAY_PORTION_FULL_PRECISION
for high-precision fees, per-hop slippage via minHopPriceX36 on
v3SwapExactInput/Output). The spokePool arg is only consumed by command
0x40 (ACROSS_V4_DEPOSIT_V3); pointing it at UnsupportedProtocol means any
attempted Across call reverts cleanly with UnsupportedProtocolError()
instead of the empty extcodesize revert that address(0) produces.

Deploy was run in two steps because Deploy-all.s.sol reads
acrossSpokePool.value directly from the task config and doesn't propagate
UnsupportedProtocol's deployed address. Step A deployed UnsupportedProtocol;
Step B wired its address into acrossSpokePool.value and deployed UR.

Chronicles required a manual patch into deployments/json/4663.json:
UR v2.1 uses CREATE2 via the canonical 0x4e59...956c deployer, which
leaves contractName=null in the broadcast file and causes chronicles to
skip it (ambiguous match against v2.0 vs v2.1 artifacts). v2.0 used plain
CREATE, which was self-labeling.

Constructor args (RouterParameters struct):
- permit2:             0x000000000022D473030F116dDEE9F6B43aC78BA3
- weth9:               0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
- v2Factory:           0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f
- v3Factory:           0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
- v2PairInitCodeHash:  0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f
- v3PoolInitCodeHash:  0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
- v4PoolManager:       0x8366a39CC670B4001A1121B8F6A443A643e40951
- v3NFTPositionMgr:    0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3
- v4PositionMgr:       0x58daec3116aae6D93017bAAea7749052E8a04fA7
- spokePool:           0x7332D11BD10d18A04B119Cd4671a96f3148002c4 (UnsupportedProtocol)
Chronicles index regeneration overwrote "Tempo Mainnet" (4217) and
"Robinhood Chain" (4663) with generic "Chain 4217" / "Chain 4663"
fallbacks. Restore the human-readable names.

These show up as the fallback when forge-chronicles' bundled chains.json
doesn't carry the chain — both of these are recent additions not yet in
chainid.network. The fix is purely cosmetic to the index page.
@david-uniswap

Copy link
Copy Markdown
Collaborator Author

Superseded by #143 which deploys the correct UR v2.1.1 (this PR shipped v2.1.0 unintentionally — briefcase initcode predated the v2.1.1 commit upstream; see #142 for the briefcase regen).

david-uniswap added a commit that referenced this pull request May 28, 2026
deploy Universal Router 2.1.1 to Robinhood Chain (replaces #141)
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