Skip to content

Deploy OETHb V3: OETHb Migration (Ethereum 011–012, Base 004–007) - #3038

Open
shahthepro wants to merge 9 commits into
masterfrom
shah/deploy-oethb-migration
Open

shahthepro wants to merge 9 commits into
masterfrom
shah/deploy-oethb-migration

Conversation

@shahthepro

@shahthepro shahthepro commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Code Change

  • Renumbers the pending deploy scripts so they run in order after what is already deployed on each chain (no logic changes):
    • Mainnet: 006_OETHbV3RemoteProxy → 011, 007_OETHbV3RemoteImpl → 012, 004_VaultMintGate → 013, 005_VaultAdminRole → 014, 006_PauseSafeModule → 015
    • Base: 001_VaultMintGate → 002, 002_PauseSafeModule → 003, 002_OETHbV3MasterProxy → 004, 003_OETHbV3MasterImpl → 005, 004_OETHbV3WOETHMigration → 006, 005_OETHbV3VaultWiring → 007, 006_OETHbV3RemoveOldStrategy → 008
  • Updates the cross-references to the renumbered scripts in script/test comments and crosschainV3/DESIGN.md
  • Records the deployments in build/deployments-1.json / build/deployments-8453.json and the descriptors in deployments/mainnet/ and deployments/base/
  • 008_OETHbV3RemoveOldStrategy (Base) and 013–015 (Mainnet) are not part of this deploy

Deployment

The strategy proxy and both adapter proxies are deployed via CreateX with matching salts, so each has the same address on both chains.

Ethereum Mainnet

Contract Address
CrossChainStrategyProxy (OETHb V3 Remote) 0xa03360b3f6d902F1b3334c0adBd5C6995d3513fe
RemoteWOTokenStrategy (impl) 0xFE69f8001b96e027C20C225Ae23d5e75687EbF1b
BridgeAdapterProxy (SuperbridgeAdapter, outbound) 0x0F12256E27E658790C404C087C38ab4f34D53360
SuperbridgeAdapter (impl) 0x05A99cB2Cf686573f96d4c25F646E1C619C602EE
BridgeAdapterProxy (CCIPAdapter, inbound) 0x03578bC4b5fB0cC0cA7A6AD05b06407ae6324a82
CCIPAdapter (impl) 0x7661a05acCAC0492D0a114909fE0126636A3c4DF

Base

Contract Address
CrossChainStrategyProxy (OETHb V3 Master) 0xa03360b3f6d902F1b3334c0adBd5C6995d3513fe
MasterWOTokenStrategy (impl) 0xC04B4EEB015D970EE3Ab21711b744787245eF22B
BridgeAdapterProxy (CCIPAdapter, outbound) 0x03578bC4b5fB0cC0cA7A6AD05b06407ae6324a82
CCIPAdapter (impl) 0xD1EB2C89f702591e5ab5e2A21AB3b0df7764D1ec
BridgeAdapterProxy (SuperbridgeAdapter, inbound) 0x0F12256E27E658790C404C087C38ab4f34D53360
SuperbridgeAdapter (impl) 0x375699507B9FbC65b13D04cCBf8e18f375EAC4C5
BridgedWOETHMigrationStrategy (impl) 0xC29788FEE651182A36b4244490E1BBb0B5C5D5Eb

Deployer transactions (both chains)

  • Strategy proxy initialized with its implementation, governor set to the chain Timelock, operator set to the Talos relayer
  • Adapter proxies initialised with the deployer as governor; lanes authorised for the strategy proxy (Mainnet also sets setCanonicalMinGas(remote, 200_000) on the Superbridge adapter); multichain strategist added on both adapters
  • Adapter governance transferGovernanced to the chain Timelock (claimed in the proposals below)

Governance

Mainnet (xOGN Governance)

Base (Timelock)

  • Proposal(s): TODO
  • Actions:
    • 005_OETHbV3MasterImpl: claimGovernance() on both adapter proxies; setOutboundAdapter(CCIPAdapter proxy) / setInboundAdapter(SuperbridgeAdapter proxy) on Master
    • 006_OETHbV3WOETHMigration: upgradeTo(BridgedWOETHMigrationStrategy) and setMaxPerBridge(1000 ether) on the BridgedWOETHStrategy proxy
    • 007_OETHbV3VaultWiring: approveStrategy(Master proxy) on the OETHb Vault (approval only, no funds move)

Deploy checklist

Two reviewers complete the following checklist:

- [ ] All deployed contracts are listed in the deploy PR's description
- [ ] Deployed contract's verified code (and all dependencies) match the code in master
- [ ] Contract constructors have correct arguments
- [ ] The transactions that interacted with the newly deployed contract match the deploy script.
- [ ] Governance proposal matches the deploy script
- [ ] Smoke tests pass after fork test execution of the governance proposal

@clement-ux

clement-ux commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator
Deployment PR Verification: #3038 (Deploy OETHb V3: OETHb Migration (Ethereum 011–012, Base 004–007))

Verified against: shah/deploy-oethb-migration@f19da29b5 (same as origin). The working tree has two untracked files outside contracts/ (brownie/runlogs/2026_10_strategist.py and output/). Neither is tracked source, so I went ahead with that noted.

Foundry scripts: mainnet/011_OETHbV3RemoteProxy, mainnet/012_OETHbV3RemoteImpl, base/004_OETHbV3MasterProxy, base/005_OETHbV3MasterImpl, base/006_OETHbV3WOETHMigration, base/007_OETHbV3VaultWiring | Networks: mainnet + base | Proposals: mainnet 91505267…800282 (xOGN Governor); base = Timelock batches via Admin Safe #64–#66

Verdict: VERIFIED. All checks pass. What's left is signing and execution on the Safes (listed at the end).

- [✅] 1. All deployed contracts are listed in the PR description. That covers 6 on Ethereum and 7 on Base, and every address matches build/deployments-{1,8453}.json. (High)
- [✅] 2. The verified code and its dependencies match the codebase. All 13 addresses are verified. sol2uml reports no differences under contracts/. The only flagged files are in dependencies/ (OZ 4.4.2, Chainlink CCIP 1.2.1), and they are identical once whitespace is ignored. (High)
- [✅] 3. Constructor args are correct. They match in position for all 7 implementations and all proxies. (High)
- [✅] 4. The initialize/interaction txs match the deploy scripts. On Ethereum, the deployer's 16 txs are in the same order as the script and their decoded args match. On Base, I confirmed through on-chain state reads. (High mainnet / Med-High Base)
- [✅] 5. The governance proposals match the deploy scripts. The mainnet proposal's getActions() is identical to the script, and the Base Safe scheduleBatch txs are identical to scripts 005/006/007. (High)
- [⏭️] 6. Smoke tests: skipped (N/A).

Details

2. sol2uml diff

Ethereum: 0xa033…13fe (CrossChainStrategyProxy), 0xFE69…bF1b (RemoteWOTokenStrategy), 0x0F12…3360 / 0x0357…4a82 (BridgeAdapterProxy), 0x05A9…02EE (SuperbridgeAdapter), 0x7661…c4DF (CCIPAdapter).
Base: 0xa033…13fe (CrossChainStrategyProxy), 0xC04B…F22B (MasterWOTokenStrategy), 0x0357…4a82 / 0x0F12…3360 (BridgeAdapterProxy), 0xD1EB…D1ec (CCIPAdapter), 0x3756…C4C5 (SuperbridgeAdapter), 0xC297…D5Eb (BridgedWOETHMigrationStrategy).

Every contracts/* file matches. The 42 files sol2uml flags are all in dependencies/: Address.sol, IERC20.sol, SafeERC20.sol and the CCIP interfaces. I diffed the Etherscan sources against the local files with whitespace stripped and found 0 real differences. The verified copies only wrap parameters differently.

3. Constructor args

┌──────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────┬──────────┐
│ Contract                             │ Script value                                                                  │ On-chain │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ RemoteWOTokenStrategy (eth)          │ (WOETHProxy, zero), WETH, OETHProxy, WOETHProxy, OETHVaultProxy               │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ SuperbridgeAdapter (eth)             │ BaseL1StandardBridge 0x3154…2C35, ccipRouterMainnet 0x8022…6f7D, WETH         │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ CCIPAdapter (eth)                    │ ccipRouterMainnet 0x8022…6f7D                                                 │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ MasterWOTokenStrategy (base)         │ (zero, OETHBaseVaultProxy), WETH 0x4200…0006                                  │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ CCIPAdapter (base)                   │ Base.CCIPRouter 0x881e…8bCD                                                   │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ SuperbridgeAdapter (base)            │ zero, Base.CCIPRouter, WETH 0x4200…0006                                       │ ✅       │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ BridgedWOETHMigrationStrategy (base) │ (zero, vault), WETH, BridgedWOETH, OETHb, OracleRouter, Master 0xa033…13fe,   │ ✅       │
│                                      │ Base.CCIPRouter, Mainnet selector 5009297550715157269                         │          │
├──────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┤
│ All proxies (CreateX CREATE2)        │ governor = deployer 0x5889…7245                                               │ ✅       │
└──────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────┴──────────┘

The Ethereum CCIP adapter proxy and the Base Superbridge adapter proxy show no args on the explorer. Both are CREATE2 deployments at the same address as their twin on the other chain, which does show the deployer arg, so their initcode is the same.

4. Initialize tx

Ethereum. The deployer txs (0x5889…7245) run in script order: proxy, impl, initialize, adapter impls, CreateX ×2, initialize ×2, authorise ×2, setCanonicalMinGas, addStrategist ×2, transferGovernance ×2.
- strategy initialize (0xae89ec84…): (0xFE69…bF1b, Timelock 0x3591…e69F, initialize(talosRelayer 0x7392…F38b)) ✅
- adapter initialize (0x3aa48549…, 0xc4e54de3…): (impl, deployer, "") ✅
- transferGovernance (0xcca074e5…, 0x289759b6…): Timelock ✅

Base. The Etherscan free tier has no Base txlist, so I read the resulting state instead:
- implementation() on all proxies ✅
- Master governor() = Timelock 0xf817…464f, operator() = talosRelayer ✅
- laneConfig(Master) = (false, 5009297550715157269, 2_000_000) ✅
- authorised(Master) = true ✅
- strategists(multichainStrategist) = true ✅
- pending governor slot = Timelock ✅

The same reads on Ethereum also pass:
- laneConfig(Remote) = (false, 15971525489660198786, 500_000)
- canonicalMinGasFor(Remote) = 200_000
- oToken/woToken/oTokenVault are correct
- the adapters' pending governor = Timelock

5. Proposal diff

Mainnet. Proposal 91505267859951030226833253700849903488427263165343640847453520847791717800282 has state() = Active. Its getActions() returns the 5 script actions in order with identical calldata:
1. claimGovernance() on the Superbridge proxy
2. claimGovernance() on the CCIP proxy
3. setOutboundAdapter(Superbridge proxy)
4. setInboundAdapter(CCIP proxy)
5. safeApproveAllTokens()

Ethereum Admin Safe #538 is castVote(91505267…800282, 1) on GovernorSix 0x1D3F…c9EC, with call and value 0. ✅

Base. Admin Safe 0x92A1…7202 sends scheduleBatch on Timelock 0xf817…464f. Each tx matches the corresponding deployments/base/operations/*.schedule.json and the script exactly (targets, payloads, salt), with predecessor 0x0 and delay 172800:
- #64 = 005: claimGovernance ×2, setOutboundAdapter(CCIP), setInboundAdapter(Superbridge), salt 0x70c7…41f9 ✅
- #65 = 006: upgradeTo(0xC297…D5Eb) and setMaxPerBridge(1000e18) on 0x80c8…f835, salt 0x338f…b629 ✅
- #66 = 007: approveStrategy(Master) on vault 0x98a0…CC93, salt 0xaaf1…4a08 ✅ (I decoded the full calldata)

This branch has not been deployed

No deployments
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