Skip to content

feat: deploy UniversalRouter 2.2.0 to mainnet, sepolia and ink - #165

Merged
dianakocsis merged 4 commits into
mainfrom
ur-2.2.0-deploy
Sep 22, 2026
Merged

dianakocsis merged 4 commits into
mainfrom
ur-2.2.0-deploy

Conversation

@dianakocsis

Copy link
Copy Markdown
Contributor

Deploys UniversalRouter 2.2.0 to mainnet, sepolia and ink, and records the results.

Deployments

Chain Address Verified
Ethereum 0xab863E752Bf67D8DCDD929EaAe9Be9dc83Fb3BbB Etherscan
Sepolia 0x5093f1CDED83d99FfEd6602dA6260672ae16787c Etherscan
Ink 0x8BbCAEb326AD590521a921C9e457Ee09F336B48c Sourcify

All three were deployed from universal-router tag 2.2.0 (64027f3) via Deploy-all, using CREATE2 with a zero salt through the deterministic deployer, matching how the previous 2.2.0 routers were deployed.

Each address was computed from the initcode before broadcasting and matched what the deploy produced. All three carry a 23,233-byte runtime, which matches the snapshot committed in Uniswap/universal-router#514. Every constructor parameter was taken from the previous 2.2.0 deployment transaction on that chain, checked to have code onchain, and cross-checked — v4PositionManager.poolManager() resolves to the v4PoolManager argument on all three, and the v2 pair init code hash was confirmed by predicting a real pool address from it.

Submodule and briefcase

src/pkgs/universal-router moves from fb25ff0 to 64027f3. That brings the Dispatcher change from universal-router#499 and moves v4-periphery from 07336f21 to a7af5b34.

The deployer initcode is regenerated to match: 24,102 to 25,193 bytes. Only the hex literal is updated — insert_initcode.py rewrites the surrounding formatting in a way that fails forge fmt, so the rest of the file, and the 30 other deployers it touched without changing their initcode, are left alone.

Build fix

src/pkgs/liquidity-launcher has no entries in the root remappings.txt, only in its own, so forge build cannot resolve its imports. It has been unbuildable since it was added in November 2025.

That was harmless until e59f730 rewrote the flatten step to run in parallel and abort on failure. Since then every create_briefcase.sh run has died on that package, which is why the committed initcode had not moved since 2026-05-27 and the Update Briefcase workflow has been failing.

Wiring it in properly is not a remapping away: process_briefcase_files.py resolves its @uniswap/v4-periphery imports against the top-level package rather than its own lib, and its nested dependencies pull in further unmapped libraries. The package has also never been part of the briefcase. Skipping it in both places restores the pre-e59f730 behaviour; the briefcase skip list is overridable via BRIEFCASE_SKIP_PKGS.

Note for anyone repeating this

forge 1.8.1 silently degrades the CREATE2 in DeployerHelper into a plain CREATE on ink, producing a nonce-derived address with no error. forge 1.5.0, which this repo's CI pins, handles it correctly. Compilation is unaffected — the deployed bytecode on mainnet and sepolia is byte-for-byte identical to a 1.5.0 build once the 49 immutable slots are masked out.

🤖 Generated with Claude Code

dianakocsis and others added 3 commits September 18, 2026 16:01
src/pkgs/liquidity-launcher has no entries in the root remappings.txt, only in
its own, so `forge build` cannot resolve its imports. It has been unbuildable
since it was added in November 2025.

That was harmless until e59f730 rewrote the flatten step to run in parallel and
abort on failure. Since then every `create_briefcase.sh` run has died on that
package, which is why the committed initcode has not moved since 2026-05-27 and
the Update Briefcase workflow has failed continuously.

Wiring it in properly is not a remapping away: process_briefcase_files.py
resolves its @uniswap/v4-periphery imports against the top-level package rather
than its own lib, and its nested dependencies pull in further unmapped
libraries. The package has also never been part of the briefcase.

Skipping it in both places restores the pre-e59f730 behaviour. The briefcase
skip list is overridable via BRIEFCASE_SKIP_PKGS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Points src/pkgs/universal-router at 64027f3, which carries tag 2.2.0. That
brings the Dispatcher change from #499 and moves v4-periphery from 07336f21 to
a7af5b34.

The deployer initcode is regenerated to match: 24,102 -> 25,193 bytes, which
deploys a 23,233-byte runtime. That size matches the snapshot committed in
universal-router#514, and the build settings are unchanged at optimizer_runs =
1, via_ir, cancun.

Only the hex literal is updated. insert_initcode.py rewrites the surrounding
formatting in a way that fails `forge fmt`, so the rest of the file, and the
other 30 deployers it touched without changing their initcode, are left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deployed from tag 2.2.0 (64027f3) via Deploy-all, CREATE2 with a zero salt
through the deterministic deployer, matching how the previous 2.2.0 routers
were deployed.

  mainnet  0xab863E752Bf67D8DCDD929EaAe9Be9dc83Fb3BbB
  sepolia  0x5093f1CDED83d99FfEd6602dA6260672ae16787c
  ink      0x8BbCAEb326AD590521a921C9e457Ee09F336B48c

Each address was computed from the initcode before broadcasting and matched
what the deploy produced. All three carry a 23,233-byte runtime, all eleven
constructor parameters were checked against the previous deployment
transaction on each chain and read back onchain, and each is verified
(Etherscan for mainnet and sepolia, Sourcify for ink).

The registry entries are normalised across the three chains: the new routers
are recorded as UniversalRouter#v2.2, and the 2.1.1 and 2.1.2 routers live on
each chain are recorded alongside them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	deployments/1.md
#	deployments/11155111.md
#	deployments/57073.md
#	deployments/json/1.json
#	deployments/json/11155111.json
#	deployments/json/57073.json
@dianakocsis
dianakocsis merged commit a289d31 into main Sep 22, 2026
4 checks passed
dianakocsis added a commit that referenced this pull request Sep 22, 2026
… all chains (#169)

The unversioned `UniversalRouter` key is what the dev portal surfaces as the
default router, but it had drifted: on the 19 chains that still carried it, it
pointed at a 2.1-generation deploy (v2.0 on ink and monad), and on eight chains
it was missing entirely -- dropped by #165 on mainnet, sepolia and ink, and
earlier by #134/#123/#126 on base, linea, x-layer, 4217 and 4326 when those
routers were version-tagged.

So `UniversalRouter` resolved either to a router the 2.1.2 migration docs are
telling integrators to move off, or to nothing at all, depending on the chain.

Alias the bare key to each chain's 2.1.2 router on all 23 chains that have one
(8 added, 15 refreshed). The versioned `UniversalRouter#v2.1.2` entries are
untouched, so pinning a specific version still works; the bare key is now a
pointer to the current recommended router.

Note this supersedes the pre-#165 values rather than restoring them -- the
default has never pointed at 2.1.2 on any chain before now.

Edits are to the `latest` map in deployments/json/<chain>.json plus the matching
summary-table row, detail section and TOC entry in deployments/<chain>.md.
Deployment History is untouched. The markdown was hand-edited rather than
regenerated because regenerate_deployment_markdown.py is not idempotent on this
tree: it reorders rows, re-adds a dropped history entry, and rewrites commit
links to the git@ form derived from the local git remote.

Not covered: monad testnet (10143) has no 2.1.2 deployed, so its default is
still the v2.0 router at 0x3ae6d8a282d67893e17aa70eBfFb33EE5aa65893. Rootstock
(30) has no UniversalRouter at all. Both need a deploy, not a registry edit.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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