memoscan
← all memos

Memo 0xa21667c1…893e24 on Ethereum

# Shut Down the sDOLA CCIP Bridge Lanes Forum: https://forum.inverse.finance/t/shut-down-the-sdola-ccip-bridge-lanes/670 ## Summary This proposal closes the idle sDOLA Chainlink CCIP integration. It removes every cross-chain lane, in both directions, across all five sDOLA token pools: the mainnet pool and the four L2 pools on Base, Optimism, Arbitrum, and Berachain. It also revokes each L2 pool's minter permission on its receipt token. The L2 changes are batched through `BridgeShutdownGovernor`, a purpose-built contract that fires all 8 cross-chain shutdown messages in a single `executeL2Shutdown()` call. The mainnet pool is closed by one direct action. The shutdown transfers no pool to a new owner. The mainnet pool stays owned by the timelock, and each L2 pool stays owned by its governance proxy. Only `GovernanceSender` ownership moves, to the governor and back to the timelock. `GovernanceSender` is delegated to the governor for the shutdown and handed back during execution. ## Rationale The sDOLA CCIP integration is not in use. Monitoring shows no live cross-chain activity and no deposits. While the integration sits idle, open bridge lanes are an unnecessary risk surface. The safe configuration when idle is to close every lane at both ends. Removing a lane on the source pool stops new transfers from starting. Removing it on the destination pool rejects any message that still arrives. Closing only one side would let a user lock funds into a lane whose far end can no longer deliver, stranding the transfer. Reopening a lane later requires a fresh governance proposal. There is no standing shortcut by design. ## The Shutdown Governor `BridgeShutdownGovernor` (`0x2A0FEC62992D2C0f1b0C598551c1627F18286F84`) sends every L2 shutdown message from a single `executeL2Shutdown()` entrypoint. It is `onlyOwner`, with the owner set to the DAO governance timelock, and it is `payable` so forwarded ETH can pay the CCIP message fees. It holds a hardcoded `L2_SHUTDOWN_MESSAGE_COUNT` of 8. The plan is fixed. The contract cannot choose destination chains, targets, or calldata. The whole batch is hardcoded and guarded by an internal assert that the message count equals 8. The shutdown removes lanes. It does not lower a rate limit. The 8 messages are four `applyChainUpdates` calls, one per L2 pool, that remove every remote chain from that pool, plus four `setMinter` calls that revoke each L2 pool's mint permission on its receipt token. The removal lists differ in length, four for Base and Arbitrum and three for Optimism and Berachain, because Optimism and Berachain do not connect to each other on-chain. Each list matches its pool's live `getSupportedChains` set exactly, so nothing reverts and no lane is left open. The governor can only act once it owns the sDOLA `GovernanceSender` (`0x4e521Fe7A9084067096d45A312B8FEeE39D5F1f3`), which is the allowlisted origin for the cross-chain messages. The proposal transfers the sender to the governor, calls `executeL2Shutdown()`, recovers unspent fees with `withdraw()` while the governor still owns the sender, then transfers the sender back to the timelock. The mainnet pool is a `LockReleaseTokenPool` and is not a minter of sDOLA, so it needs no minter revocation. Only its remote-chain connections are removed, and that runs as the direct mainnet action. ## Configuration Chain selectors: | Chain | Selector | |---|---| | Ethereum | `5009297550715157269` | | Base | `15971525489660198786` | | Optimism | `3734403246176062136` | | Arbitrum | `4949039107694359620` | | Berachain | `1294465214383781161` | Core contracts: | Contract | Address | |---|---| | BridgeShutdownGovernor | `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | | GovernanceSender (sDOLA) | `0x4e521Fe7A9084067096d45A312B8FEeE39D5F1f3` | | DAO governance timelock (owner) | `0x926dF14a23BE491164dCF93f4c468A50ef659D5B` | | Mainnet token pool (LockReleaseTokenPool) | `0x05eEe76f456C51Be0459EC1c0a78bf177B2c877C` | L2 token pools, receipt tokens, and governance proxies: | Chain | Token pool | Receipt token | Governance proxy | |---|---|---|---| | Base | `0xd84e1B7e1a7A8D49167884855c3985ef4bCa45aB` | `0xCa78ee4544ec5a33Af86F1E786EfC7d3652bf005` | `0x1C064265E053D23d120c518fDBB542e6537f82d1` | | Optimism | `0x8404024d8F74Ad2D20E82c184816B64D4184A018` | `0xfc63C9c8Ba44AE89C01265453Ed4F427C80cBd4E` | `0xaF956837AF704D825c1FCbE2651D5c3c37AD5289` | | Arbitrum | `0xbbc28DB61DF26B76D5F7D5Eed17eD4D6C278460e` | `0x7a1e123e41458aabaB8068BFed6010D8f9480898` | `0x607bCd974bB69C78eCdbf0B68748B791bBa24d94` | | Berachain | `0x8Bbd036d018657E454F679E7C4726F7a8ECE2773` | `0x02eaa69646183c069FC2B64F15923F27B9CF3b03` | `0x1992AF61FBf8ee38741bcc57d636CAA22A1a7702` | Action 3 carries the CCIP fee budget for the 8 messages. Fees are paid from the `GovernanceSender` balance, and unused ETH is recovered by action 4. Fund it by setting the value on action 3, or by sending ETH to the `GovernanceSender` before execution. ## On-Chain Actions Ownership moves through Chainlink's two-step `ConfirmedOwner` pattern. Action 4 recovers unspent CCIP fees and must run after `executeL2Shutdown()` and before the sender is transferred back, while the governor still owns the sender. | # | Target | Function | Value | Arguments | |---|---|---|---|---| | 1 | GovernanceSender `0x4e521Fe7A9084067096d45A312B8FEeE39D5F1f3` | `transferOwnership(address)` | 0 | governor `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | | 2 | Governor `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | `acceptGovernanceSenderOwnership()` | 0 | `0x` | | 3 | Governor `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | `executeL2Shutdown()` | **CCIP fees** | `0x` *(fires 8 L2 messages)* | | 4 | Governor `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | `withdraw(address)` | 0 | timelock `0x926dF14a23BE491164dCF93f4c468A50ef659D5B` | | 5 | Governor `0x2A0FEC62992D2C0f1b0C598551c1627F18286F84` | `transferGovernanceSenderOwnership(address)` | 0 | timelock `0x926dF14a23BE491164dCF93f4c468A50ef659D5B` | | 6 | GovernanceSender `0x4e521Fe7A9084067096d45A312B8FEeE39D5F1f3` | `acceptOwnership()` | 0 | `0x` | | 7 | Mainnet pool `0x05eEe76f456C51Be0459EC1c0a78bf177B2c877C` | `applyChainUpdates(uint64[],ChainUpdate[])` | 0 | remove `[15971525489660198786, 3734403246176062136, 4949039107694359620, 1294465214383781161]`; add `[]` |