Files
proxmox/docs/07-ccip/CW_BRIDGE_APPROACH.md
defiQUG b3a8fe4496
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
chore: sync all changes to Gitea
- Config, docs, scripts, and backup manifests
- Submodule refs unchanged (m = modified content in submodules)

Made-with: Cursor
2026-03-02 11:37:34 -08:00

4.7 KiB
Raw Permalink Blame History

cW* Bridge Approach (Chosen Strategy)

Created: 2026-02-27
Status: Decided — Option 2 (dedicated cW* receiver)
Related: CW_BRIDGE_TASK_LIST.md


1. Decision (A1)

Chosen: Option 2 — Deploy dedicated cW receiver per chain.*

  • Option 1 (extend existing bridge): Would require changing CCIPWETH9Bridge / CCIPRelayBridge to accept more than WETH9 and mint cW* in ccipReceive. That mixes WETH and cW* in one contract and complicates upgrades.
  • Option 2 (dedicated receiver): Use a contract that only handles cW* mint-on-receive and burn-on-send (e.g. TwoWayTokenBridgeL2 or a minimal CCIPReceiverCW). Keeps WETH bridges unchanged; cW* flow is separate and easier to reason about.

Concrete choice: Use TwoWayTokenBridgeL2 (or equivalent) per (chain, token) — one deployment per chain for cWUSDT and one for cWUSDC, or a generic receiver that supports multiple cW* via message data. CompliantWrappedToken is extended with burnFrom so TwoWayTokenBridgeL2s outbound burnFrom works (Phase C1).


2. Flow 138 → chain (lock c* on 138, mint cW* on destination)

  1. User on Chain 138 locks cUSDT (or cUSDC) in a sender contract (e.g. UniversalCCIPBridge, or a dedicated c*→cW* bridge on 138).
  2. Sender sends a CCIP message to the destination chain with:
    • Receiver: Dedicated cW* receiver (e.g. TwoWayTokenBridgeL2 instance for cWUSDT on that chain).
    • Data: abi.encode(recipient, amount) (same as TwoWayTokenBridgeL2).
    • Token amounts: Either none (lock-and-mint: 138 locks c*, destination mints cW*) or source token as specified by the bridge design.
  3. On destination chain, the cW receiver*s ccipReceive is called by the CCIP router. It decodes (recipient, amount) and calls cWUSDT.mint(recipient, amount) (receiver must have MINTER_ROLE on the cW* token).
  4. User on destination receives cWUSDT.

Contracts implementing receive: Dedicated cW* receiver (e.g. TwoWayTokenBridgeL2 with mirroredToken = cWUSDT or cWUSDC). Not CCIPWETH9Bridge / CCIPRelayBridge (they remain WETH-only).

Contracts implementing send (138 side): UniversalCCIPBridge (if extended for c* and destination = cW* receiver), or a dedicated “Lock c* and send CCIP” contract that configures receiver = TwoWayTokenBridgeL2 on the target chain.


3. Flow chain → 138 (burn cW* on chain, release c* on 138)

  1. User on destination chain calls the cW receiver*s outbound function (e.g. TwoWayTokenBridgeL2.burnAndSend(destSelector, recipient, amount)).
  2. Receiver burns cW* from the user (cWUSDT.burnFrom(user, amount) — requires CompliantWrappedToken to implement burnFrom; see Phase C1) and sends a CCIP message to Chain 138 with receiver = L1 bridge and data (recipient, amount).
  3. On Chain 138, the L1 bridge (or release contract) receives the message and releases cUSDT to the recipient (e.g. transfer from escrow or mint if L1 is mintable).

Contracts implementing burn-and-send: Same dedicated cW* receiver (TwoWayTokenBridgeL2) that has BURNER_ROLE on the cW* token and implements burnAndSend. CompliantWrappedToken must expose burnFrom for TwoWayTokenBridgeL2.

Contracts implementing receive on 138: L1 bridge or release contract that holds or mints c* and credits the recipient.


4. Contract summary

Role Contract(s)
cW token (destination chain)* CompliantWrappedToken (cWUSDT, cWUSDC). MINTER_ROLE and BURNER_ROLE granted to the dedicated receiver (e.g. TwoWayTokenBridgeL2).
Receive on destination (mint cW)* TwoWayTokenBridgeL2 (or CCIPReceiverCW). Constructor(router, cWUSDT, feeToken). Implements ccipReceive → mint(recipient, amount).
Send from destination (burn cW, send CCIP)* Same TwoWayTokenBridgeL2. burnAndSend → burnFrom(user) → ccipSend to 138.
Send from 138 (lock c, send CCIP)* UniversalCCIPBridge (with c* and cW* receiver config) or dedicated lock-and-send contract. Receiver address = TwoWayTokenBridgeL2 on destination.
Receive on 138 (release c)* L1 bridge or release contract (existing or new) that credits recipient when message received from destination chain.

5. References