- Config, docs, scripts, and backup manifests - Submodule refs unchanged (m = modified content in submodules) Made-with: Cursor
10 KiB
cW* Bridge Support — Detailed Task List
Created: 2026-02-27
Updated: 2026-02-27 — In-repo tasks completed (Phase A, C1, F); operator tasks (D, E, C2–C3) have runbook.
Context: After setting CW_BRIDGE_<CHAIN> from the deployed bridge suite (CCIPRelayBridge on Mainnet, CCIPWETH9_BRIDGE_* on other chains), this document reviews the note that those contracts may need extension for cW* and turns it into a concrete task list.
Completion summary (in-repo): Phase A (approach decided and documented), Phase C1 (CompliantWrappedToken.burnFrom added, tests added), Phase F (docs and runbook). Phase B marked N/A (Option 2 chosen). Remaining steps script: run-cw-remaining-steps.sh — --dry-run (default), --deploy, --update-mapping, --verify. Phase D/E and C2–C3: run script with --deploy when RPC/keys are set; then set CWUSDT_/CWUSDC_ in .env and run --update-mapping; see CW_DEPLOY_AND_WIRE_RUNBOOK.md.
1. Note reviewed
Note (from previous setup):
"Mainnet uses CCIPRelayBridge; other chains use CCIPWETH9_BRIDGE_. Those contracts are currently WETH-oriented; if they do not yet implement cW* mint/burn, they will need to be extended (or replaced with a cW*-capable receiver) before cW* transfers work."*
Verification (checks performed):
| Check | Result |
|---|---|
| CCIPRelayBridge.sol (Mainnet) | ccipReceive only accepts message.tokenAmounts[0].token == weth9 and does IERC20(weth9).transfer(recipient, amount). Does not call any cW.mint().* |
| CCIPWETH9Bridge.sol (all chains) | Same: validates token == weth9, then transfer(recipient, amount). Does not mint cW.* |
| CCIPWETH10Bridge.sol | Same for WETH10; no cW* logic. |
| CompliantWrappedToken.sol | Has mint, burn, and burnFrom (BURNER_ROLE). burnFrom added in Phase C1 for TwoWayTokenBridgeL2 outbound. |
| TwoWayTokenBridgeL2.sol | ccipReceive calls IMintableERC20(mirroredToken).mint(recipient, amount) — would mint cW* if mirroredToken = cWUSDT/cWUSDC. Outbound uses burnFrom; CompliantWrappedToken does not implement burnFrom. |
| DeployCWTokens.s.sol | Grants MINTER_ROLE and BURNER_ROLE to CW_BRIDGE_ADDRESS (per-chain in .env). So the address we set will have roles, but the contract code at that address (CCIPWETH9Bridge/CCIPRelayBridge) never calls mint/burn on cW*. |
Conclusion: The current bridge suite is WETH-only. Granting MINTER/BURNER to it allows deployment of cW* but does not enable cross-chain mint/burn of cW* until the receiver logic is extended or a dedicated cW* receiver is deployed.
2. Checks performed (summary)
- Contract audit: CCIPRelayBridge, CCIPWETH9Bridge, CCIPWETH10Bridge — ccipReceive only transfers the received token (WETH9/WETH10), no mint path.
- CompliantWrappedToken: mint/burn roles and interface; no burnFrom.
- TwoWayTokenBridgeL2: Mint-on-receive pattern; requires burnFrom for outbound.
- .env: CW_BRIDGE_ set from existing deployed addresses (Mainnet, Cronos, BSC, Polygon, Gnosis, Avalanche, Base, Arbitrum, Optimism).
- Deploy path: DeployCWTokens grants roles to CW_BRIDGE_*; deploy script uses per-chain bridge from .env.
3. Detailed task list
Phase A: Decide and document approach
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| A1 | Decide cW receive strategy:* (1) Extend existing CCIPWETH9Bridge/CCIPRelayBridge to support cW* mint in ccipReceive, or (2) Deploy dedicated cW* receiver per chain (e.g. TwoWayTokenBridgeL2 or new CCIPReceiverCW). | Operator/Dev | Option 2 chosen. | ✅ Done |
| A2 | Document chosen approach in docs/07-ccip/CW_BRIDGE_APPROACH.md (create): flow 138→chain (lock c* on 138, mint cW* on dest), chain→138 (burn cW*, release c*), and which contract(s) implement receive/send. |
Dev | ✅ Done |
Phase B: Contract changes (if extending existing bridge)
Not applied — Option 2 (dedicated receiver) chosen; Phase B is the alternative path if extending existing bridges instead.
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| B1 | Design bridge extension: In CCIPWETH9Bridge (and/or CCIPRelayBridge), allow ccipReceive to accept more than WETH9: e.g. token whitelist (cWUSDT, cWUSDC) and on receive either transfer (if token is WETH9) or mint (if token is cW* and bridge has MINTER_ROLE). | Dev | Match data encoding (recipient, amount, sender, nonce) with existing. | N/A (Option 2) |
| B2 | Implement and test: Add tests for ccipReceive with token = cWUSDT and assert cWUSDT.mint(recipient, amount) and balance increase. | Dev | N/A (Option 2) | |
| B3 | Deploy upgraded bridge (or new implementation + upgrade if proxy) on each chain; update .env and config if address changes. | Operator | If new contract, set CW_BRIDGE_ to new address and re-grant MINTER/BURNER on cW* to new bridge. | N/A (Option 2) |
Phase C: Contract changes (if dedicated cW* receiver)
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| C1 | CompliantWrappedToken: Add burnFrom(address from, uint256 amount) that checks BURNER_ROLE and calls burn(from, amount) (or implement ERC20Burnable and grant BURNER to bridge). |
Dev | Required if using TwoWayTokenBridgeL2 for outbound. | ✅ Done |
| C2 | Deploy TwoWayTokenBridgeL2 (or new CCIPReceiverCW) per chain: constructor(router, cWUSDT, feeToken). Configure destination (Chain 138 selector, L1 bridge address). | Operator | TwoWayTokenBridgeL2 is not upgradeable; one deployment per (chain, token) or generic with token in message. See CW_DEPLOY_AND_WIRE_RUNBOOK.md. | Pending |
| C3 | Point CW_BRIDGE_ to new receiver and re-run DeployCWTokens so MINTER/BURNER are on the new receiver, or grant roles to new receiver after deploy. | Operator | If receiver is separate from CCIPWETH9_BRIDGE, set CW_BRIDGE_ to receiver address. | Pending |
| C4 | Chain 138 send side: Ensure a sender/bridge on 138 sends CCIP messages with receiver = new cW* receiver on destination and data encoding (recipient, amount). | Dev/Operator | Documented in CW_BRIDGE_APPROACH.md. | ✅ Documented |
Phase D: Deploy cW* and wire config
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| D1 | Run cW deploy* on each target chain: ./scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh --deploy-cw (with CW_BRIDGE_ already set). |
Operator | Records CWUSDT_, CWUSDC_ in script output. Runbook: CW_DEPLOY_AND_WIRE_RUNBOOK.md § D1. | Operator |
| D2 | Set CWUSDT_ and CWUSDC_ in smom-dbis-138/.env from deploy output for each chain. | Operator | Runbook § D2. | Operator |
| D3 | Update token-mapping-multichain.json for each chain: set addressTo for Compliant_USDT_cW, Compliant_USDC_cW (and Compliant_EURC_cW if deployed) from CWUSDT_/CWUSDC_ addresses. |
Operator | Replace 0x0 placeholders. Runbook § D3. | Operator |
| D4 | Verify on-chain: On each chain, confirm cWUSDT/cWUSDC exist, and bridge/receiver address has MINTER_ROLE and BURNER_ROLE. | Operator | Runbook § D4. | Operator |
Phase E: Relay and send path (138 → other chains)
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| E1 | Relay service (138→Mainnet): If using CCIPRelayBridge for cW*, extend relay to support cUSDT/cUSDC: relay must send CCIP with token = cUSDT (or lock-and-mint semantics) and destination = Mainnet bridge; Mainnet bridge must mint cWUSDT. | Operator/Dev | See RELAY_BRIDGE_ADD_LINK_SUPPORT_RUNBOOK.md pattern (extend bridge or new receiver). Runbook § E1. | Operator |
| E2 | Direct CCIP (138→chain): If Chain 138 uses UniversalCCIPBridge or CCIPWETH9Bridge to send c* to destination, add destination config for c* and ensure receiver on destination mints cW*. | Dev | Documented in approach; runbook § E2. | Documented |
| E3 | Test E2E: Lock cUSDT on 138, trigger send, verify cWUSDT minted on destination to recipient. | Operator | Runbook § E3. | Operator |
Phase F: Documentation and runbooks
| # | Task | Owner | Notes | Status |
|---|---|---|---|---|
| F1 | Update docs/11-references/CW_TOKENS_AND_NETWORKS.md: Add section "Bridge support status" — which chains have bridge code that mints cW* (none until Phase B or C done). | Dev | ✅ Done | |
| F2 | Update docs/04-configuration/C_TO_CW_MAPPER_MAPPING.md: Note that addressTo for _cW is 0x0 until cW* deployed and that bridge must support mint. | Dev | ✅ Done | |
| F3 | Create runbook (e.g. docs/07-ccip/CW_DEPLOY_AND_WIRE_RUNBOOK.md): steps to deploy cW* on a new chain, set CW_BRIDGE_, update token-mapping, verify roles. | Dev | ✅ Done |
4. Dependency order
- A1 → A2 (decide approach, document).
- A1 → B or C (implementation depends on choice).
- B or C → D1 (deploy cW* after bridge/receiver can mint; or deploy cW* and grant roles to existing bridge, then extend bridge later so it actually mints).
- D1 → D2, D3, D4 (config and verify).
- D + (B or C) → E (send path and relay).
- F can be done in parallel or after each phase.
Minimal path to “cW deployed and roles set” (no cross-chain mint yet):* D1, D2, D4 — already possible with current .env. To actually mint cW on receive*, complete Phase A, then B or C, then E.
5. References
- CW_TOKENS_AND_NETWORKS.md
- C_TO_CW_MAPPER_MAPPING.md
- CW_BRIDGE_APPROACH.md — Chosen approach (Option 2) and flows.
- CW_DEPLOY_AND_WIRE_RUNBOOK.md — Operator steps for D1–D4, E1–E3.
- RELAY_BRIDGE_ADD_LINK_SUPPORT_RUNBOOK.md (pattern for extending bridge)
smom-dbis-138/contracts/relay/CCIPRelayBridge.sol,contracts/ccip/CCIPWETH9Bridge.solsmom-dbis-138/contracts/bridge/TwoWayTokenBridgeL2.solsmom-dbis-138/contracts/tokens/CompliantWrappedToken.sol(includesburnFromfor TwoWayTokenBridgeL2)