From 77c818fc2d3f426f67385fa384e0eec99c67ad71 Mon Sep 17 00:00:00 2001 From: Joxess Date: Wed, 18 Sep 2024 18:02:09 -0300 Subject: [PATCH 01/10] interop: add ETH Shared Lockbox design doc Co-authored-by: ng --- protocol/eth-shared-lockbox.md | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 protocol/eth-shared-lockbox.md diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md new file mode 100644 index 00000000..de1bd7ac --- /dev/null +++ b/protocol/eth-shared-lockbox.md @@ -0,0 +1,120 @@ +# Purpose + +*The document presented below is part of the [Interoperability project](https://github.com/ethereum-optimism/optimism/issues/10899).* + +This document discusses possible solutions to address the constraints on ETH withdrawals resulting from the introduction of interop and `SuperchainWETH` that share ETH liquidity across a set of OP Chains. + +# Summary + +With interoperable ETH, withdrawals may fail if the referenced `OptimismPortal`lacks sufficient ETH—especially for large amounts or on OP Chains with low liquidity—since ETH liquidity isn't shared at the L1 level. Several solutions have been explored to prevent users from getting stuck. Currently, the Superchain design favors the `SharedLockbox` as the most effective solution. Key considerations are detailed at the end of the document. + +# Problem Statement + Context + +With the introduction of interop, `SuperchainWETH` is created as a medium to move ETH across a set of interoperable chains, instead of using native ETH. To enable users to convert `SuperchainWETH` into native ETH, `ETHLiquidity` is also introduced, containing a sufficiently large virtual pool of native ETH, which can only be used for this purpose. As a result, ETH can be shared through all interconnected chains. + +However, one remaining problem to solve relates to [ETH withdrawals](https://github.com/ethereum-optimism/specs/issues/362). Currently, with Interop, the amount of ETH on an L2 can differ from what is deposited in the respective `OptimismPortal`. This mismatch can interfere with the finalization of withdrawals, especially if a request requires more ETH than is actually deposited at a given time. + +As a side note, this problem is also closely related to the process of how an OP Chain enters and leaves an interoperable set of chains. Not defining this scenario could create a problem in the future. + +# Prior considerations + +Before explaining the proposed solution, it is important to note that there are essential assumptions that underpin the whole design. + +### Chain Management + +This refers to how OP Chains will be governed within an interoperable set of chains (also called a "cluster"). Once governance principles are well-established from the perspective of the technological stack, state transitions can be secured, enabling ETH to be uniformly integrated and secured across the entire cluster. Currently, this is achieved by addressing the following: + +- The interoperable set of chains will be governed by an entity responsible for: + - Approving chains to join the cluster. This is done either through trusted deployment methods (e.g., OP Stack Manager) or by approval after security checks are performed. + - Managing (adding and removing) chains within the interoperable graph. + - Approving protocol upgrades for all involved. + - Taking action if an OP Chain decides not to follow the established standard (e.g. Expresses a desire to leave the cluster.). +- Each chain is capable of defending against any maliciously claimed state transition. Ideally, this is accomplished through a set of security features at the proof level, such as permissionless proofs, capability of proving executions that are related to interop executions, and the presence of the Guardian role for the whole system. This is indifferent to what proof system is used (ZK, fault proofs, etc.). +- Joining a cluster will automatically enable the use of `SuperchainWETH` for the specific set of chains defined by the `dependencyManager`. + +### SuperchainWETH usage + +As mentioned above, in any OP Chain within the cluster where interop is enabled, the use of `SuperchainWETH` will be activated. As a result, equivalence between ETH deposits and the actual ETH supply will vary from the outset. In a world with freedom of movement, all ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. This is an unavoidable scenario that deserves careful consideration and is crucial for understanding the following sections. + +# Solution + +We propose an L1 shared liquidity design, achieved by introducing a new `SharedLockbox` in L1 that serves as a singleton ETH contract for the entire interoperable set of chains. New ETH deposits will be forwarded to the lockbox, and the same applies to ETH withdrawals. This could also serve as the singleton contract for gas tokens in the case of CGT chains. + +### Spec changes + +The core changes proposed are the following: + +- Introduce `SharedLockbox` which accepts deposits and withdrawals of ETH and Gas Tokens as well. +- Modify `OptimismPortal` to forward ETH deposits into `SharedLockbox` and allow extraction of ETH when a withdrawal is finalized. +- Maintain an on-chain list (through `SystemConfigInterop` or another contract if already defined) that registers the chains that are part of the cluster. This allows `SharedLockbox` to validate a withdrawal from a chain that is part of the cluster. + +This would require a one-time L1 liquidity migration process for each chain. Newly deployed chains via `OPSM` should use the `SharedLockbox` from the beginning. + +### Joining the Cluster + +From the point of view of a chain deployed via `OPSM`, we suggest adopting `SharedLockbox` even when there is no interoperable set established for it. Since the security is guarded by the security council and governance, it should not represent a risk. + +For existing chains, the `OptimismPortal` should incorporate a new gated function that hardcodes the sending of ETH to the `SharedLockbox` contract and that can only be called by a trusted entity, e.g., the Security Council. This function should also emit an event which the off-chain components can use to track how much ETH was initially moved from a chain to the `SharedLockbox`, which may be required in case the chain wishes to opt out of the cluster in the future. + +```solidity +function joinInteropCluster() external onlySecurityCouncil { + uint256 balance = address(this).balance; + address(SHARED_LOCKBOX).call{value: balance}(""); + emit JoinedInteropCluster(chainId, balance); +} + +``` + +### Opt-out the cluster + +A process to opt out of the cluster should be possible. For this to work properly, it is first necessary to track the actual amount of ETH that pertains to the L2 at a given time. As an open system, we need to monitor the net flows between L1-L2 and L2-L2. For L1-L2, this involves tracking deposits and withdrawals through an L1 deposit mapping. For L2-L2, an `InteropETHTransferred` mapping is introduced for the same purpose. When interop is enabled, the following elements need to be present: + +- The initial migrated ETH, serves as the starting amount. +- A deposit mapping that tracks ETH successfully deposited and finalized withdrawals. +- The `InteropETHTransferred` mapping is implemented when `SuperchainWETH` interoperability transfers are enabled. + +Then, the opt-out process would be performed as follows: + +1. Disconnect the chain from the interop set. +2. Pause new deposits. +3. Waiting time for stabilizing pending interop messages and deposits. +4. Trigger the migration by porting `InteropETHTransferred` back to L1. + +One path could be having two functions to initiate and finalize the migration, or directly via a protocol upgrade. + +The resultant math to calculate the exact ETH amount to migrate will be: + +ETH to Migrate = (1)initial balance + (2)deposit mapping + (3)Netflow ETH interop transferred. +Note that (1) should be zero if the chain is deployed using `SharedLockbox` by default. (2) and (3) are integers as their number could become negative. For (3) to be an accurate value, there should be no pending messages waiting to expire. + +### Impact + +The whole work can be split into two big phases: + +1. **First phase**: Modify the necessary core L1 contracts, adding the `InteropETHTransferred` counter for `SuperchainWETH` total transfer history and the standardized process for new and existing chains to adopt the `SharedLockbox`. +2. **Second phase**: Develop the needed pieces for the opt-out process. + +All phases require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, `SystemConfigInterop`, `SuperchainWETH` transfer mapping in L2, and possibly others. This also includes the scripts to perform the migration. + +# Alternatives Considered + +### Reverts on L2 + +One alternative is not to share liquidity at the L1 level and instead prevent withdrawals from being stuck by reverting them on L2. This approach requires tracking the exact ETH balance in L2 via deposits and withdrawals. An `ETHBalance` counter would increment with new mints from deposits and decrease with successful `initiateWithdrawal` calls. + +This method would require minimal changes to `L1Block` and adjustments to how `TransactionDeposited` is processed to validate new ETH counts. Additionally, it necessitates porting the initial balance as part of an upgrade transaction. + +The problem with L2 reverts is that it breaks the ETH withdrawal guarantee invariant and still exposes the system to solvency issues. Based on previous feedback, this would affect existing applications and pre-deployed contracts such as the current `FeeVault` withdrawal contract logic. + +### **Permission to withdraw ETH from a different Portal** + +[Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if Chain A connects to Chain B and Chain B connects to Chain C (Chain A ⮀ Chain B ⮀ Chain C), but Chain A does not connect directly to Chain C (Chain A ↮ Chain C), a withdrawal initiated from A could be finalized by taking funds from C if needed. + +The implementation would require iterating through the dependency set, determined on L1 to find the next `OptimismPortal` with available funds. This approach incurs more modifications to the `OptimismPortal`, increasing complexity. + +# Risks & Uncertainties + +- **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. +- **Unfinalized interop messages**: For `InteropETHTransferred` to work properly, we need to figure out what it means for the current rollback message approach, especially relevant at the moment of the opt-out. + - For example, one main scenario to avoid is when the `InteropETHTransferred` value is pulled back to L1, but there are still expired messages ready to be claimed, resulting in the L2 ETH supply being greater than the amount reported at the L1 level. +- **Interoperable CGT**: how to make ETH interoperable with Custom Gas Token chains, as well as gas tokens for normal OP Chains. If the Shared Liquidity approach is accepted, this will be prioritized. \ No newline at end of file From 7a89e33fb28e38527b67d163c080dc0986d4f692 Mon Sep 17 00:00:00 2001 From: Joxess Date: Wed, 30 Oct 2024 01:01:52 -0300 Subject: [PATCH 02/10] update doc with latest changes --- protocol/eth-shared-lockbox.md | 152 +++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 54 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index de1bd7ac..ed762cef 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -1,12 +1,12 @@ # Purpose -*The document presented below is part of the [Interoperability project](https://github.com/ethereum-optimism/optimism/issues/10899).* +*The document presented below is part of the [Interoperability project](https://github.com/orgs/ethereum-optimism/projects/71/views/1?sliceBy%5Bvalue%5D=skeletor-spaceman).* -This document discusses possible solutions to address the constraints on ETH withdrawals resulting from the introduction of interop and `SuperchainWETH` that share ETH liquidity across a set of OP Chains. +This document discusses possible solutions to address the constraints on ETH withdrawals resulting from the introduction of interop and `SuperchainWETH` that share ETH liquidity across a set of interoperable OP Chains. # Summary -With interoperable ETH, withdrawals may fail if the referenced `OptimismPortal`lacks sufficient ETH—especially for large amounts or on OP Chains with low liquidity—since ETH liquidity isn't shared at the L1 level. Several solutions have been explored to prevent users from getting stuck. Currently, the Superchain design favors the `SharedLockbox` as the most effective solution. Key considerations are detailed at the end of the document. +With interoperable ETH, withdrawals may fail if the referenced `OptimismPortal` lacks sufficient ETH—especially for large amounts or on OP Chains with low liquidity—since ETH liquidity isn't shared at the L1 level. To prevent users from being stuck, several solutions have been explored. Currently, the Superchain design favors the `SharedLockbox` and the `DependencySetManager` as the most effective solution. # Problem Statement + Context @@ -14,87 +14,132 @@ With the introduction of interop, `SuperchainWETH` is created as a medium to mov However, one remaining problem to solve relates to [ETH withdrawals](https://github.com/ethereum-optimism/specs/issues/362). Currently, with Interop, the amount of ETH on an L2 can differ from what is deposited in the respective `OptimismPortal`. This mismatch can interfere with the finalization of withdrawals, especially if a request requires more ETH than is actually deposited at a given time. -As a side note, this problem is also closely related to the process of how an OP Chain enters and leaves an interoperable set of chains. Not defining this scenario could create a problem in the future. +This means a solution is needed to achieve a truly shared `SuperchainWETH` via shared ETH liquidity given an interoperable set of chains. # Prior considerations -Before explaining the proposed solution, it is important to note that there are essential assumptions that underpin the whole design. +Before explaining the proposed solution, it is important to note that there are essential assumptions that underpin the whole design: the Shared Security Model, Unified Chain Governance and Superchain WETH activation. -### Chain Management +### Shared Security Model -This refers to how OP Chains will be governed within an interoperable set of chains (also called a "cluster"). Once governance principles are well-established from the perspective of the technological stack, state transitions can be secured, enabling ETH to be uniformly integrated and secured across the entire cluster. Currently, this is achieved by addressing the following: +The security model for the set of interoperable chains (commonly called a "cluster") is shared across all involved chains, ensuring that all state transitions are secured. For example, the shared security model allows for defending against any maliciously claimed state transition for any chain within the cluster. This is accomplished through a set of security features at the proof level, such as permissionless proposing, interop-provable proofs (also called shared proofs), and the presence of a single Guardian role across the entire system. This model is independent of the proof system used (e.g., ZK, fault proofs, etc.). -- The interoperable set of chains will be governed by an entity responsible for: - - Approving chains to join the cluster. This is done either through trusted deployment methods (e.g., OP Stack Manager) or by approval after security checks are performed. - - Managing (adding and removing) chains within the interoperable graph. - - Approving protocol upgrades for all involved. - - Taking action if an OP Chain decides not to follow the established standard (e.g. Expresses a desire to leave the cluster.). -- Each chain is capable of defending against any maliciously claimed state transition. Ideally, this is accomplished through a set of security features at the proof level, such as permissionless proofs, capability of proving executions that are related to interop executions, and the presence of the Guardian role for the whole system. This is indifferent to what proof system is used (ZK, fault proofs, etc.). -- Joining a cluster will automatically enable the use of `SuperchainWETH` for the specific set of chains defined by the `dependencyManager`. +### Unified Chain Governance -### SuperchainWETH usage +OP Chains will be governed within a common Chain Cluster governance entity (the Collective). Currently, this entity is responsible for: -As mentioned above, in any OP Chain within the cluster where interop is enabled, the use of `SuperchainWETH` will be activated. As a result, equivalence between ETH deposits and the actual ETH supply will vary from the outset. In a world with freedom of movement, all ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. This is an unavoidable scenario that deserves careful consideration and is crucial for understanding the following sections. +- **Ensuring chains are consistent at the implementation side**, achieved either through trusted deployment methods (e.g., OP Contracts Manager) or by approval after security checks are performed. +- **Approving protocol upgrades** for all chains involved. +- **Adding new chains** to join into the interoperable set, managing the `dependencyManager` role. The final decision is up to governance. +- **Remove existing chains** from the interoperable set. However, such a removal should not be executed without a contingency plan due to the significant implications this could entail. + +### Shared Bridging and SuperchainWETH usage + +In any OP Chain that joins the cluster, the use of `SuperchainWETH` is activated. As a result, the equivalence between ETH deposits and withdrawal history and the actual ETH supply will vary from the outset. In a world with freedom of movement, all real ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. # Solution -We propose an L1 shared liquidity design, achieved by introducing a new `SharedLockbox` in L1 that serves as a singleton ETH contract for the entire interoperable set of chains. New ETH deposits will be forwarded to the lockbox, and the same applies to ETH withdrawals. This could also serve as the singleton contract for gas tokens in the case of CGT chains. +The existing problem and considerations motivate us to propose an L1 shared liquidity design through the introduction of a new `SharedLockbox` on L1, which serves as a singleton contract for ETH, given a defined set of interoperable chains. To ensure consistency, the `DependencySetManager` is also introduced to manage the dependency set that the lockbox uses as a source of truth. New ETH deposits will be directed to the lockbox, with the same process applying to ETH withdrawals. + +## Spec changes -### Spec changes +The core changes proposed are as follows: -The core changes proposed are the following: +- Introduce the `DependencySetManager` contract: This contract manages and tracks the dependency graph. +- Introduce the `SharedLockbox` contract: It acts as an escrow for ETH, receiving deposits and allows withdrawals from approved `OptimismPortal2` contracts. The `DependencySetManager` contract serves as the source of truth of the lockbox. +- Modify the `SystemConfigInterop`: Add `addDependencies` and `removeDependencies` functions to accept an array of `_chainId` values. +- Modify the `L1BlockInterop`: To maintain consistency with `SystemConfigInterop`. +- Modify the `OptimismPortal2`/`OptimismPortalInterop`: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the same process applying when `finalizeWithdrawal` is called. -- Introduce `SharedLockbox` which accepts deposits and withdrawals of ETH and Gas Tokens as well. -- Modify `OptimismPortal` to forward ETH deposits into `SharedLockbox` and allow extraction of ETH when a withdrawal is finalized. -- Maintain an on-chain list (through `SystemConfigInterop` or another contract if already defined) that registers the chains that are part of the cluster. This allows `SharedLockbox` to validate a withdrawal from a chain that is part of the cluster. +### Managing `DependencySetManager` -This would require a one-time L1 liquidity migration process for each chain. Newly deployed chains via `OPSM` should use the `SharedLockbox` from the beginning. +This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfigInterop` contract involved. Being In the simple dependency the case, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. -### Joining the Cluster +Adding a new chain can be done as follows: -From the point of view of a chain deployed via `OPSM`, we suggest adopting `SharedLockbox` even when there is no interoperable set established for it. Since the security is guarded by the security council and governance, it should not represent a risk. +1. `registerChain` is called, which adds the chain to the registry (`chainId` value, `SystemConfig` address, `OptimismPortal2` address) but does not add it to the dependency set. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) or the [OP Contracts Manager](https://specs.optimism.io/experimental/op-contracts-manager.html?highlight=chain#chain-id-source-of-truth) can be used as the source of truth to add chains that have been verified as compatible with this integration. +2. An OP-governed address, who has the role to call `addChain` with the new `chainId`. + 1. `addChain` then calls each `SystemConfigInterop` in the existing `dependencySet` list. + 1. For the chain being added, it triggers `addDependency` with `chainId1`, `chainId2`, … `chainIdn`. + 2. For all existing chains, it triggers `addDependency` with `chainId` as the newly added chain. + 2. Updates the dependency graph (mapping or array). + 3. Emits an event for step (1). -For existing chains, the `OptimismPortal` should incorporate a new gated function that hardcodes the sending of ETH to the `SharedLockbox` contract and that can only be called by a trusted entity, e.g., the Security Council. This function should also emit an event which the off-chain components can use to track how much ETH was initially moved from a chain to the `SharedLockbox`, which may be required in case the chain wishes to opt out of the cluster in the future. +A code example for step (2) would look like as this: ```solidity -function joinInteropCluster() external onlySecurityCouncil { - uint256 balance = address(this).balance; - address(SHARED_LOCKBOX).call{value: balance}(""); - emit JoinedInteropCluster(chainId, balance); +// Mapping from chainId to SystemConfigInterop address +mapping(uint256 => address) public systemConfigInterops; +// Mapping to check if a chainId is in the dependency set +mapping(uint256 => bool) public alreadyAdded; +// Current dependency set list +uint256[] public dependencySet; + +// Function to add a chain to the dependency set +function addChain(uint256 chainId) external onlyOwner { + require(systemConfigInterops[chainId] != address(0), "DependencySetManager: Chain not registered"); + require(!isRegistered[chainId], "DependencySetManager: Chain already in dependency set"); + + // For the chain being added, call addDependencies with existing chainIds + if (dependencySet.length > 0) { + for (uint256 i = 0; i < dependencySet.length; i++) { + ISystemConfigInterop(systemConfigInterops[chainId]).addDependency(dependencySet[i]); + } + } + + // For each existing chain, call addDependencies with the new chainId + for (uint256 i = 0; i < dependencySet.length; i++) { + ISystemConfigInterop(systemConfigInterops[dependencySet[i]]).addDependency(chainId); + } + // Update the dependency set + dependencySet.push(chainId); + isRegistered[chainId] = true; + + emit ChainAdded(chainId); } - + ``` -### Opt-out the cluster +For `removeChain`, the process would follows the same logic. + +Note that, under the specified flow, the dependency set consistently maintains the form of a [complete graph](https://en.wikipedia.org/wiki/Complete_graph) at all times. -A process to opt out of the cluster should be possible. For this to work properly, it is first necessary to track the actual amount of ETH that pertains to the L2 at a given time. As an open system, we need to monitor the net flows between L1-L2 and L2-L2. For L1-L2, this involves tracking deposits and withdrawals through an L1 deposit mapping. For L2-L2, an `InteropETHTransferred` mapping is introduced for the same purpose. When interop is enabled, the following elements need to be present: +### `addDependencies` and `removeDependencies` in `SystemConfigInterop` and `L1BlockInterop` + +The purpose of these functions is to extend the current `SystemConfigInterop` implementation by allowing multiple `chainId` values to be added in a single call by passing them as an array. There are a few ways to pass these values through `setConfig`: one is making a single call and triggering the `TransactionDeposited` event, or by looping through the current `addDependency`/`removeDependency` functions. + +With this optimization, the `DependencySetManager` can simplify the number of calls, as follows: + +```solidity +function addChain(uint256 chainId) external onlyOwner { + // ... + if (dependencySet.length > 0) { + // If we can input an array chainId values thorugh addDependencies function + ISystemConfigInterop(newChainSystemConfig).addDependencies(dependencySet); + } + // ... +``` -- The initial migrated ETH, serves as the starting amount. -- A deposit mapping that tracks ETH successfully deposited and finalized withdrawals. -- The `InteropETHTransferred` mapping is implemented when `SuperchainWETH` interoperability transfers are enabled. +### `SharedLockbox` implementation -Then, the opt-out process would be performed as follows: +A minimal set of functions should include: -1. Disconnect the chain from the interop set. -2. Pause new deposits. -3. Waiting time for stabilizing pending interop messages and deposits. -4. Trigger the migration by porting `InteropETHTransferred` back to L1. +- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal2`. +- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal2`. -One path could be having two functions to initiate and finalize the migration, or directly via a protocol upgrade. +Access control for `lockETH` and `unlockETH` is validated against the list reated by `registerChain`. -The resultant math to calculate the exact ETH amount to migrate will be: +### `OptimismPortal2` upgrade process -ETH to Migrate = (1)initial balance + (2)deposit mapping + (3)Netflow ETH interop transferred. -Note that (1) should be zero if the chain is deployed using `SharedLockbox` by default. (2) and (3) are integers as their number could become negative. For (3) to be an accurate value, there should be no pending messages waiting to expire. +A one-time L1 liquidity migration is required for each approved chain. By using an intermediate contract during the upgrade, all ETH held by the `OptimismPortal` can be transferred to the `SharedLockbox` within the `initialize` function. After this migration, the `OptimismPortal` is upgraded to the new version with the desired functionality. -### Impact +Importantly, the entire upgrade process—including migrating the ETH to the `SharedLockbox` and updating the `OptimismPortal` to the latest version—can be executed in a single transaction. This approach ensures a migration without the necessity of maintaining a persistent migration function in the final contract. -The whole work can be split into two big phases: +Only chains registered in the `DependencySetManager` should be approved to join the `SharedLockbox`. Once approved, the `SharedLockbox` address is added in the `constructor` and `initialize` functions for each `OptimismPortal2`. -1. **First phase**: Modify the necessary core L1 contracts, adding the `InteropETHTransferred` counter for `SuperchainWETH` total transfer history and the standardized process for new and existing chains to adopt the `SharedLockbox`. -2. **Second phase**: Develop the needed pieces for the opt-out process. +## Impact -All phases require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, `SystemConfigInterop`, `SuperchainWETH` transfer mapping in L2, and possibly others. This also includes the scripts to perform the migration. +The following components require an audit of the new and modified contracts: `OptimismPortal2`, `SharedLockbox`, `SystemConfigInterop`, `L1BlockInterop`, and `DependencySetManager`. This also includes the scripts necessary to perform the migration. # Alternatives Considered @@ -108,13 +153,12 @@ The problem with L2 reverts is that it breaks the ETH withdrawal guarantee invar ### **Permission to withdraw ETH from a different Portal** -[Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if Chain A connects to Chain B and Chain B connects to Chain C (Chain A ⮀ Chain B ⮀ Chain C), but Chain A does not connect directly to Chain C (Chain A ↮ Chain C), a withdrawal initiated from A could be finalized by taking funds from C if needed. +[Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if we have a dependency set composed by Chain A, B and C, a withdrawal initiated from A could be finalized by using funds from B and C if needed. The implementation would require iterating through the dependency set, determined on L1 to find the next `OptimismPortal` with available funds. This approach incurs more modifications to the `OptimismPortal`, increasing complexity. # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. -- **Unfinalized interop messages**: For `InteropETHTransferred` to work properly, we need to figure out what it means for the current rollback message approach, especially relevant at the moment of the opt-out. - - For example, one main scenario to avoid is when the `InteropETHTransferred` value is pulled back to L1, but there are still expired messages ready to be claimed, resulting in the L2 ETH supply being greater than the amount reported at the L1 level. -- **Interoperable CGT**: how to make ETH interoperable with Custom Gas Token chains, as well as gas tokens for normal OP Chains. If the Shared Liquidity approach is accepted, this will be prioritized. \ No newline at end of file +- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` and `removeChain` functions call every `SystemConfigInterop`, which will increase in number over time. This would lead to significant gas expenditure as the number of chains continues to grow. +- **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. \ No newline at end of file From 258f7ded05badf2a84cd2448aee80d47904a91ca Mon Sep 17 00:00:00 2001 From: Joxess Date: Thu, 31 Oct 2024 12:14:28 -0300 Subject: [PATCH 03/10] fix: grammar --- protocol/eth-shared-lockbox.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index ed762cef..9ee566d4 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -53,7 +53,7 @@ The core changes proposed are as follows: ### Managing `DependencySetManager` -This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfigInterop` contract involved. Being In the simple dependency the case, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. +This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfigInterop` contract involved. In the case of a simple dependency, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. Adding a new chain can be done as follows: @@ -65,7 +65,7 @@ Adding a new chain can be done as follows: 2. Updates the dependency graph (mapping or array). 3. Emits an event for step (1). -A code example for step (2) would look like as this: +A code example for step (2) would look like this: ```solidity // Mapping from chainId to SystemConfigInterop address From bb46e30dc7524ca0e347cfec280c51c6abb61ec2 Mon Sep 17 00:00:00 2001 From: Joxes <91908708+Joxess@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:33:32 -0300 Subject: [PATCH 04/10] update prior considerations --- protocol/eth-shared-lockbox.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index 9ee566d4..cb118e00 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -30,12 +30,12 @@ OP Chains will be governed within a common Chain Cluster governance entity (the - **Ensuring chains are consistent at the implementation side**, achieved either through trusted deployment methods (e.g., OP Contracts Manager) or by approval after security checks are performed. - **Approving protocol upgrades** for all chains involved. -- **Adding new chains** to join into the interoperable set, managing the `dependencyManager` role. The final decision is up to governance. -- **Remove existing chains** from the interoperable set. However, such a removal should not be executed without a contingency plan due to the significant implications this could entail. +- **Adding new chains** to the interoperable set, and managing the `dependencyManager` role. The final decision is up to governance and chains cannot be removed afterwards. +- **Replacing chain servicers** for existing chains if they fail to satisfy technical requirements. ### Shared Bridging and SuperchainWETH usage -In any OP Chain that joins the cluster, the use of `SuperchainWETH` is activated. As a result, the equivalence between ETH deposits and withdrawal history and the actual ETH supply will vary from the outset. In a world with freedom of movement, all real ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. +In any OP Chain that joins the cluster, it is assumed that `SuperchainWETH` has been deployed in advance before being added to the interoperable graph. As a result, the equivalence between ETH deposits and withdrawal history and the actual ETH supply will vary from the outset. In a world with freedom of movement, all real ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. # Solution @@ -161,4 +161,4 @@ The implementation would require iterating through the dependency set, determine - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. - **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` and `removeChain` functions call every `SystemConfigInterop`, which will increase in number over time. This would lead to significant gas expenditure as the number of chains continues to grow. -- **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. \ No newline at end of file +- **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. From 4c49463d0c541f86bdf7fbf1f1ff9acf3a3f082b Mon Sep 17 00:00:00 2001 From: Joxes <91908708+Joxess@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:44:59 -0300 Subject: [PATCH 05/10] remove removeChain function --- protocol/eth-shared-lockbox.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index cb118e00..25766639 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -100,8 +100,6 @@ function addChain(uint256 chainId) external onlyOwner { ``` -For `removeChain`, the process would follows the same logic. - Note that, under the specified flow, the dependency set consistently maintains the form of a [complete graph](https://en.wikipedia.org/wiki/Complete_graph) at all times. ### `addDependencies` and `removeDependencies` in `SystemConfigInterop` and `L1BlockInterop` @@ -160,5 +158,5 @@ The implementation would require iterating through the dependency set, determine # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. -- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` and `removeChain` functions call every `SystemConfigInterop`, which will increase in number over time. This would lead to significant gas expenditure as the number of chains continues to grow. +- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfigInterop`, which will increase in number over time. This would lead to significant gas expenditure as the number of chains continues to grow. - **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. From 887b02253af015bcde4e685d5c6aec842814d345 Mon Sep 17 00:00:00 2001 From: Joxes <91908708+Joxess@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:46:34 -0300 Subject: [PATCH 06/10] Move SystemConfig optimization suggestions to final section --- protocol/eth-shared-lockbox.md | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index 25766639..b91756a9 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -47,8 +47,6 @@ The core changes proposed are as follows: - Introduce the `DependencySetManager` contract: This contract manages and tracks the dependency graph. - Introduce the `SharedLockbox` contract: It acts as an escrow for ETH, receiving deposits and allows withdrawals from approved `OptimismPortal2` contracts. The `DependencySetManager` contract serves as the source of truth of the lockbox. -- Modify the `SystemConfigInterop`: Add `addDependencies` and `removeDependencies` functions to accept an array of `_chainId` values. -- Modify the `L1BlockInterop`: To maintain consistency with `SystemConfigInterop`. - Modify the `OptimismPortal2`/`OptimismPortalInterop`: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the same process applying when `finalizeWithdrawal` is called. ### Managing `DependencySetManager` @@ -80,14 +78,14 @@ function addChain(uint256 chainId) external onlyOwner { require(systemConfigInterops[chainId] != address(0), "DependencySetManager: Chain not registered"); require(!isRegistered[chainId], "DependencySetManager: Chain already in dependency set"); - // For the chain being added, call addDependencies with existing chainIds + // For the chain being added, call addDependency with existing chainIds if (dependencySet.length > 0) { for (uint256 i = 0; i < dependencySet.length; i++) { ISystemConfigInterop(systemConfigInterops[chainId]).addDependency(dependencySet[i]); } } - // For each existing chain, call addDependencies with the new chainId + // For each existing chain, call addDependency with the new chainId for (uint256 i = 0; i < dependencySet.length; i++) { ISystemConfigInterop(systemConfigInterops[dependencySet[i]]).addDependency(chainId); } @@ -102,22 +100,6 @@ function addChain(uint256 chainId) external onlyOwner { Note that, under the specified flow, the dependency set consistently maintains the form of a [complete graph](https://en.wikipedia.org/wiki/Complete_graph) at all times. -### `addDependencies` and `removeDependencies` in `SystemConfigInterop` and `L1BlockInterop` - -The purpose of these functions is to extend the current `SystemConfigInterop` implementation by allowing multiple `chainId` values to be added in a single call by passing them as an array. There are a few ways to pass these values through `setConfig`: one is making a single call and triggering the `TransactionDeposited` event, or by looping through the current `addDependency`/`removeDependency` functions. - -With this optimization, the `DependencySetManager` can simplify the number of calls, as follows: - -```solidity -function addChain(uint256 chainId) external onlyOwner { - // ... - if (dependencySet.length > 0) { - // If we can input an array chainId values thorugh addDependencies function - ISystemConfigInterop(newChainSystemConfig).addDependencies(dependencySet); - } - // ... -``` - ### `SharedLockbox` implementation A minimal set of functions should include: @@ -158,5 +140,5 @@ The implementation would require iterating through the dependency set, determine # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. -- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfigInterop`, which will increase in number over time. This would lead to significant gas expenditure as the number of chains continues to grow. +- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfigInterop`, which will increase in number over time. This could lead to significant gas expenditure as the number of chains continues to grow. One possible solution could be to extend the current `addDependency`/`removeDependency` to accept an array of `chainId` values in a single deposit call. The same reasoning could apply to `L1Block`. - **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. From 6424b990b887b21930fc75d86d3f5c7b4092ca3a Mon Sep 17 00:00:00 2001 From: Joxes <91908708+Joxess@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:09:41 -0300 Subject: [PATCH 07/10] fix contract names --- protocol/eth-shared-lockbox.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index b91756a9..a942039c 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -46,18 +46,18 @@ The existing problem and considerations motivate us to propose an L1 shared liqu The core changes proposed are as follows: - Introduce the `DependencySetManager` contract: This contract manages and tracks the dependency graph. -- Introduce the `SharedLockbox` contract: It acts as an escrow for ETH, receiving deposits and allows withdrawals from approved `OptimismPortal2` contracts. The `DependencySetManager` contract serves as the source of truth of the lockbox. -- Modify the `OptimismPortal2`/`OptimismPortalInterop`: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the same process applying when `finalizeWithdrawal` is called. +- Introduce the `SharedLockbox` contract: It acts as an escrow for ETH, receiving deposits and allows withdrawals from approved `OptimismPortal` contracts. The `DependencySetManager` contract serves as the source of truth of the lockbox. +- Modify the `OptimismPortal`: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the same process applying when `finalizeWithdrawal` is called. ### Managing `DependencySetManager` -This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfigInterop` contract involved. In the case of a simple dependency, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. +This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfig` contract involved. In the case of a simple dependency, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. Adding a new chain can be done as follows: -1. `registerChain` is called, which adds the chain to the registry (`chainId` value, `SystemConfig` address, `OptimismPortal2` address) but does not add it to the dependency set. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) or the [OP Contracts Manager](https://specs.optimism.io/experimental/op-contracts-manager.html?highlight=chain#chain-id-source-of-truth) can be used as the source of truth to add chains that have been verified as compatible with this integration. +1. `registerChain` is called, which adds the chain to the registry (`chainId` value, `SystemConfig` address, `OptimismPortal` address) but does not add it to the dependency set. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) or the [OP Contracts Manager](https://specs.optimism.io/experimental/op-contracts-manager.html?highlight=chain#chain-id-source-of-truth) can be used as the source of truth to add chains that have been verified as compatible with this integration. 2. An OP-governed address, who has the role to call `addChain` with the new `chainId`. - 1. `addChain` then calls each `SystemConfigInterop` in the existing `dependencySet` list. + 1. `addChain` then calls each `SystemConfig` in the existing `dependencySet` list. 1. For the chain being added, it triggers `addDependency` with `chainId1`, `chainId2`, … `chainIdn`. 2. For all existing chains, it triggers `addDependency` with `chainId` as the newly added chain. 2. Updates the dependency graph (mapping or array). @@ -66,8 +66,8 @@ Adding a new chain can be done as follows: A code example for step (2) would look like this: ```solidity -// Mapping from chainId to SystemConfigInterop address -mapping(uint256 => address) public systemConfigInterops; +// Mapping from chainId to SystemConfig address +mapping(uint256 => address) public systemConfigs; // Mapping to check if a chainId is in the dependency set mapping(uint256 => bool) public alreadyAdded; // Current dependency set list @@ -75,19 +75,19 @@ uint256[] public dependencySet; // Function to add a chain to the dependency set function addChain(uint256 chainId) external onlyOwner { - require(systemConfigInterops[chainId] != address(0), "DependencySetManager: Chain not registered"); + require(systemConfigs[chainId] != address(0), "DependencySetManager: Chain not registered"); require(!isRegistered[chainId], "DependencySetManager: Chain already in dependency set"); // For the chain being added, call addDependency with existing chainIds if (dependencySet.length > 0) { for (uint256 i = 0; i < dependencySet.length; i++) { - ISystemConfigInterop(systemConfigInterops[chainId]).addDependency(dependencySet[i]); + ISystemConfig(systemConfigs[chainId]).addDependency(dependencySet[i]); } } // For each existing chain, call addDependency with the new chainId for (uint256 i = 0; i < dependencySet.length; i++) { - ISystemConfigInterop(systemConfigInterops[dependencySet[i]]).addDependency(chainId); + ISystemConfig(systemConfigs[dependencySet[i]]).addDependency(chainId); } // Update the dependency set dependencySet.push(chainId); @@ -104,22 +104,22 @@ Note that, under the specified flow, the dependency set consistently maintains t A minimal set of functions should include: -- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal2`. -- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal2`. +- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal`. +- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal`. Access control for `lockETH` and `unlockETH` is validated against the list reated by `registerChain`. -### `OptimismPortal2` upgrade process +### `OptimismPortal` upgrade process A one-time L1 liquidity migration is required for each approved chain. By using an intermediate contract during the upgrade, all ETH held by the `OptimismPortal` can be transferred to the `SharedLockbox` within the `initialize` function. After this migration, the `OptimismPortal` is upgraded to the new version with the desired functionality. Importantly, the entire upgrade process—including migrating the ETH to the `SharedLockbox` and updating the `OptimismPortal` to the latest version—can be executed in a single transaction. This approach ensures a migration without the necessity of maintaining a persistent migration function in the final contract. -Only chains registered in the `DependencySetManager` should be approved to join the `SharedLockbox`. Once approved, the `SharedLockbox` address is added in the `constructor` and `initialize` functions for each `OptimismPortal2`. +Only chains registered in the `DependencySetManager` should be approved to join the `SharedLockbox`. Once approved, the `SharedLockbox` address is added in the `constructor` and `initialize` functions for each `OptimismPortal`. ## Impact -The following components require an audit of the new and modified contracts: `OptimismPortal2`, `SharedLockbox`, `SystemConfigInterop`, `L1BlockInterop`, and `DependencySetManager`. This also includes the scripts necessary to perform the migration. +The following components require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, and `DependencySetManager`. This also includes the scripts necessary to perform the migration. # Alternatives Considered @@ -140,5 +140,5 @@ The implementation would require iterating through the dependency set, determine # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. -- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfigInterop`, which will increase in number over time. This could lead to significant gas expenditure as the number of chains continues to grow. One possible solution could be to extend the current `addDependency`/`removeDependency` to accept an array of `chainId` values in a single deposit call. The same reasoning could apply to `L1Block`. +- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfig`, which will increase in number over time. This could lead to significant gas expenditure as the number of chains continues to grow. One possible solution could be to extend the current `addDependency`/`removeDependency` to accept an array of `chainId` values in a single deposit call. The same reasoning could apply to `L1Block`. - **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. From b9ecd91a6c2c41dab65bbe7a8de8fe5ebe124498 Mon Sep 17 00:00:00 2001 From: Joxes <91908708+Joxess@users.noreply.github.com> Date: Wed, 13 Nov 2024 06:59:06 -0300 Subject: [PATCH 08/10] Update dependency set management and upgrade process --- protocol/eth-shared-lockbox.md | 117 ++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 54 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index a942039c..be5c8efd 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -6,7 +6,7 @@ This document discusses possible solutions to address the constraints on ETH wit # Summary -With interoperable ETH, withdrawals may fail if the referenced `OptimismPortal` lacks sufficient ETH—especially for large amounts or on OP Chains with low liquidity—since ETH liquidity isn't shared at the L1 level. To prevent users from being stuck, several solutions have been explored. Currently, the Superchain design favors the `SharedLockbox` and the `DependencySetManager` as the most effective solution. +With interoperable ETH, withdrawals may fail if the referenced `OptimismPortal` lacks sufficient ETH—especially for large amounts or on OP Chains with low liquidity—since ETH liquidity isn't shared at the L1 level. To prevent users from being stuck, several solutions have been explored. Currently, the Superchain design favors the `SharedLockbox` and extends the `SuperchainConfig` as a *dependency set manager*, which is considered the most effective solution. # Problem Statement + Context @@ -35,67 +35,72 @@ OP Chains will be governed within a common Chain Cluster governance entity (the ### Shared Bridging and SuperchainWETH usage -In any OP Chain that joins the cluster, it is assumed that `SuperchainWETH` has been deployed in advance before being added to the interoperable graph. As a result, the equivalence between ETH deposits and withdrawal history and the actual ETH supply will vary from the outset. In a world with freedom of movement, all real ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. +In any OP Chain that joins the cluster, it is assumed that `SuperchainWETH` has been deployed in advance prior to being added to the interoperable graph. As a result, the equivalence between ETH deposits and withdrawal history and the actual ETH supply will vary from the outset. In a world with freedom of movement, all real ETH liquidity is theoretically shared across the entire cluster eventually, regardless of how deposits are handled. # Solution -The existing problem and considerations motivate us to propose an L1 shared liquidity design through the introduction of a new `SharedLockbox` on L1, which serves as a singleton contract for ETH, given a defined set of interoperable chains. To ensure consistency, the `DependencySetManager` is also introduced to manage the dependency set that the lockbox uses as a source of truth. New ETH deposits will be directed to the lockbox, with the same process applying to ETH withdrawals. +The existing problem and considerations motivate us to propose an L1 shared liquidity design through the introduction of a new `SharedLockbox` on L1, which serves as a singleton contract for ETH, given a defined set of interoperable chains. To ensure consistency, the `SuperchainConfig` is extended to act as the *dependency set manager*, controlling the op-governed dependency set that the lockbox uses as a source of truth. New ETH deposits will be directed to the lockbox, with the same process applied to ETH withdrawals. -## Spec changes +### Spec changes +The core proposed changes are as follows: +- **Modify the `SuperchainConfig` contract**: Extend this contract to manage the dependency set of each chain, taking ownership of the `dependencyManager` role for each `SystemConfig`. +- **Introduce the `SharedLockbox` contract**: This contract acts as an escrow for ETH, receiving deposits and allowing withdrawals from approved `OptimismPortal` contracts. The `SuperchainConfig` contract serves as the source of truth of the lockbox. +- **Modify the `OptimismPortal`**: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the inverse process applying when `finalizeWithdrawal` is called. -The core changes proposed are as follows: +### Managing op-governed dependency set through `SuperchainConfig` -- Introduce the `DependencySetManager` contract: This contract manages and tracks the dependency graph. -- Introduce the `SharedLockbox` contract: It acts as an escrow for ETH, receiving deposits and allows withdrawals from approved `OptimismPortal` contracts. The `DependencySetManager` contract serves as the source of truth of the lockbox. -- Modify the `OptimismPortal`: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the same process applying when `finalizeWithdrawal` is called. +The `SuperchainConfig` contract will serve as the single point for managing the dependency set of a cluster and will be managed by the admin as occurs in other L1 OP contracts. This contract assumes the role of `dependencyManager` for every `SystemConfig` contract involved. Since the dependency graph follows a simple dependency, it only stores a mapping (or array) of chains added, e.g. given a `chainId`. -### Managing `DependencySetManager` +```solidity +// Mapping from chainId to SystemConfig address +mapping(uint256 _chainId => ISystemConfig) public systemConfigs; + +// Current dependency set list +EnumerableSet.UintSet private _dependencySet; +``` -This contract serves as the single point for managing the dependency set of a cluster and is expected to be managed by an admin in the same manner as other L1 OP contracts (proxiable). This contract assumes the role of `dependencyManager` for every `SystemConfig` contract involved. In the case of a simple dependency, the `DependencySetManager` only stores a mapping (or array) of chains added, e.g. given a `chainId`. +Adding a new chain can be done by introducing a new function called `addChain`. The process would look as follows: -Adding a new chain can be done as follows: +1. The `updater` calls the function with `chainId` and `SystemConfig`. +2. An external call is made to each `SystemConfig` from already added chains with the new `chainId`. +3. The new `SystemConfig` is called to add all previously existing `chainId` from `SuperchainConfig` to itself. +4. Each call concludes by emitting a `DepositedTransaction` event. +5. The `OptimismPortal` address is stored in the `Sharedlockbox` mapping. +6. Each chain asynchronously includes each new deposit and updates `dependencySet` in `L1Block`. -1. `registerChain` is called, which adds the chain to the registry (`chainId` value, `SystemConfig` address, `OptimismPortal` address) but does not add it to the dependency set. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) or the [OP Contracts Manager](https://specs.optimism.io/experimental/op-contracts-manager.html?highlight=chain#chain-id-source-of-truth) can be used as the source of truth to add chains that have been verified as compatible with this integration. -2. An OP-governed address, who has the role to call `addChain` with the new `chainId`. - 1. `addChain` then calls each `SystemConfig` in the existing `dependencySet` list. - 1. For the chain being added, it triggers `addDependency` with `chainId1`, `chainId2`, … `chainIdn`. - 2. For all existing chains, it triggers `addDependency` with `chainId` as the newly added chain. - 2. Updates the dependency graph (mapping or array). - 3. Emits an event for step (1). +The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) or the [OP Contracts Manager](https://specs.optimism.io/experimental/op-contracts-manager.html?highlight=chain#chain-id-source-of-truth) can be used as the source of truth to add chains that have been verified beforehand as compatible. -A code example for step (2) would look like this: +A code example would look like this: ```solidity -// Mapping from chainId to SystemConfig address -mapping(uint256 => address) public systemConfigs; -// Mapping to check if a chainId is in the dependency set -mapping(uint256 => bool) public alreadyAdded; -// Current dependency set list -uint256[] public dependencySet; - -// Function to add a chain to the dependency set -function addChain(uint256 chainId) external onlyOwner { - require(systemConfigs[chainId] != address(0), "DependencySetManager: Chain not registered"); - require(!isRegistered[chainId], "DependencySetManager: Chain already in dependency set"); - - // For the chain being added, call addDependency with existing chainIds - if (dependencySet.length > 0) { - for (uint256 i = 0; i < dependencySet.length; i++) { - ISystemConfig(systemConfigs[chainId]).addDependency(dependencySet[i]); - } - } - - // For each existing chain, call addDependency with the new chainId - for (uint256 i = 0; i < dependencySet.length; i++) { - ISystemConfig(systemConfigs[dependencySet[i]]).addDependency(chainId); +function addChain(uint256 _chainId, address _systemConfig) external { + require(msg.sender == updater(), "Unauthorized"); + + // Add to the dependency set and check it is not already added (`add()` returns false if it already exists) + require(_dependencySet.add(_chainId), "Chain already added"); + + // Store the system config + systemConfigs[_chainId] = _systemConfig; + + // Loop through the dependency set and update the dependency for each chain + for (uint256 i; i < _dependencySet.length() - 1; i++) { + uint256 currentId = _dependencySet.at(i); + + // Skip recently added chain + if (_chainId == currentId) continue; + + systemConfigs[currentId].addDependency(_chainId); + + systemConfigs[_chainId].addDependency(currentId); } - // Update the dependency set - dependencySet.push(chainId); - isRegistered[chainId] = true; - emit ChainAdded(chainId); + address portal = _systemConfig.optimismPortal(); + + // Authorize the portal on the shared lockbox + SHARED_LOCKBOX.authorizePortal(portal); + + emit ChainAdded(_chainId, _systemConfig, portal); } - ``` Note that, under the specified flow, the dependency set consistently maintains the form of a [complete graph](https://en.wikipedia.org/wiki/Complete_graph) at all times. @@ -107,19 +112,19 @@ A minimal set of functions should include: - `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal`. - `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal`. -Access control for `lockETH` and `unlockETH` is validated against the list reated by `registerChain`. +Access control for `lockETH` and `unlockETH` is validated against the mapping of authorized `OptimismPortal` addresses. ### `OptimismPortal` upgrade process -A one-time L1 liquidity migration is required for each approved chain. By using an intermediate contract during the upgrade, all ETH held by the `OptimismPortal` can be transferred to the `SharedLockbox` within the `initialize` function. After this migration, the `OptimismPortal` is upgraded to the new version with the desired functionality. +A one-time L1 liquidity migration is required for each approved chain. By using an intermediate contract denominated `LiquidityMigrator` during the upgrade, all ETH held by the `OptimismPortal` can be transferred to the `SharedLockbox`. This intermediate contract functions similarly to `StorageSetter` and is used for the sole purpose of transferring the ETH balance. After this migration, the `OptimismPortal` is upgraded to the new version with the desired functionality. -Importantly, the entire upgrade process—including migrating the ETH to the `SharedLockbox` and updating the `OptimismPortal` to the latest version—can be executed in a single transaction. This approach ensures a migration without the necessity of maintaining a persistent migration function in the final contract. +Importantly, the entire upgrade process—including migrating the ETH to the `SharedLockbox` and updating the `OptimismPortal` to the latest version—can be executed in a single batched transaction. This approach ensures migration without the necessity of maintaining a persistent migration function in the final contract. -Only chains registered in the `DependencySetManager` should be approved to join the `SharedLockbox`. Once approved, the `SharedLockbox` address is added in the `constructor` and `initialize` functions for each `OptimismPortal`. +Note that migration processes may not be uniform and may vary according to the status of the chain seeking to join the OP-governed interoperable set. As stated in the previous section, chains are expected to ensure they reach the approved, OP Stack version. In practice, different migration paths could be implemented, for example, to allow chains to use the `SharedLockbox` from inception or migrate from a previous one, for example. ## Impact -The following components require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, and `DependencySetManager`. This also includes the scripts necessary to perform the migration. +The following components require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, and `SuperchainConfig`. This also includes the scripts necessary to perform the migration. # Alternatives Considered @@ -135,10 +140,14 @@ The problem with L2 reverts is that it breaks the ETH withdrawal guarantee invar [Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if we have a dependency set composed by Chain A, B and C, a withdrawal initiated from A could be finalized by using funds from B and C if needed. -The implementation would require iterating through the dependency set, determined on L1 to find the next `OptimismPortal` with available funds. This approach incurs more modifications to the `OptimismPortal`, increasing complexity. +The implementation would require iterating through the dependency set, determined on L1 to find the next `OptimismPortal` with available funds. This also means `OptimismPortal` would need to have authorization and validation logic to allow to extraction ETH given an arbitrary request dictated by the loop. +**Implementation and security considerations** +Since both approaches rely on multiple `OptimismPortal` contracts and access controls, the Shared Lockbox design stays as the minimal way to implement a shared liquidity approach. Instead, allowing a looping withdrawal into each `OptimismPortal` increases the code complexity and surface of bugs during the iterative checking. + # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains. -- **Necessity of gas optimizations**: the `DependencySetManager`’s `addChain` function call every `SystemConfig`, which will increase in number over time. This could lead to significant gas expenditure as the number of chains continues to grow. One possible solution could be to extend the current `addDependency`/`removeDependency` to accept an array of `chainId` values in a single deposit call. The same reasoning could apply to `L1Block`. -- **Chain list consistency around OP contracts**: OP Chains can have different statuses over time. This is reflected by the potential presence of several lists, such as those in the `OPCM` and the `DependencySetManager`. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. +- **Necessity of gas optimizations**: the `addChain` function calls every `SystemConfig`, which will increase in number over time. This could lead to significant gas expenditure as the number of chains continues to grow. One possible solution could be to extend the current `addDependency`/`removeDependency` to accept an array of `chainId` values in a single deposit call. The same reasoning could apply to `L1Block`. +- **Chain list consistency around OP contracts**: OP Chains can have different statuses over time, being potentially reflected under the presence of several lists, such as those in the `OPCM`, the `SuperchainConfig` and other registries. It would make sense to coordinate on implementing the most ideal chain registry for all expected use cases, including those described in this doc. +- **`chainId` authenticity**: As mentioned above, dependency set management relies on the `chainId` value. This necessitates ensuring that each `chainId` is unique within the chain list and correctly references a `SystemConfig`. This also raises the question of whether `chainId` should be stored directly within the `SystemConfig` for added verification. From 300d05311bfd5fd1e8411f7ac6a54107e7f3d8a9 Mon Sep 17 00:00:00 2001 From: gotzenx <78360669+gotzenx@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:02:26 -0300 Subject: [PATCH 09/10] fix: snippet & mermaid --- protocol/eth-shared-lockbox.md | 81 +++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index be5c8efd..9b35ec2f 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -47,7 +47,7 @@ The core proposed changes are as follows: - **Introduce the `SharedLockbox` contract**: This contract acts as an escrow for ETH, receiving deposits and allowing withdrawals from approved `OptimismPortal` contracts. The `SuperchainConfig` contract serves as the source of truth of the lockbox. - **Modify the `OptimismPortal`**: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the inverse process applying when `finalizeWithdrawal` is called. -### Managing op-governed dependency set through `SuperchainConfig` +### Managing op-governed dependency set through `SuperchainConfig` The `SuperchainConfig` contract will serve as the single point for managing the dependency set of a cluster and will be managed by the admin as occurs in other L1 OP contracts. This contract assumes the role of `dependencyManager` for every `SystemConfig` contract involved. Since the dependency graph follows a simple dependency, it only stores a mapping (or array) of chains added, e.g. given a `chainId`. @@ -74,32 +74,32 @@ A code example would look like this: ```solidity function addChain(uint256 _chainId, address _systemConfig) external { - require(msg.sender == updater(), "Unauthorized"); + require(msg.sender == updater(), "Unauthorized"); + // Add to the dependency set and check it is not already added (`add()` returns false if it already exists) + require(_dependencySet.add(_chainId), "Chain already added"); - // Add to the dependency set and check it is not already added (`add()` returns false if it already exists) - require(_dependencySet.add(_chainId), "Chain already added"); + // Store the system config + systemConfigs[_chainId] = _systemConfig; - // Store the system config - systemConfigs[_chainId] = _systemConfig; + // Loop through the dependency set and update the dependency for each chain + for (uint256 i; i < _dependencySet.length() - 1; i++) { - // Loop through the dependency set and update the dependency for each chain - for (uint256 i; i < _dependencySet.length() - 1; i++) { - uint256 currentId = _dependencySet.at(i); - - // Skip recently added chain - if (_chainId == currentId) continue; - - systemConfigs[currentId].addDependency(_chainId); - - systemConfigs[_chainId].addDependency(currentId); - } + uint256 currentId = _dependencySet.at(i); - address portal = _systemConfig.optimismPortal(); + // Skip recently added chain + if (_chainId == currentId) continue; - // Authorize the portal on the shared lockbox - SHARED_LOCKBOX.authorizePortal(portal); + systemConfigs[currentId].addDependency(_chainId); - emit ChainAdded(_chainId, _systemConfig, portal); + systemConfigs[_chainId].addDependency(currentId); + } + + address portal = _systemConfig.optimismPortal(); + + // Authorize the portal on the shared lockbox + SHARED_LOCKBOX.authorizePortal(portal); + + emit ChainAdded(_chainId, _systemConfig, portal); } ``` @@ -122,6 +122,45 @@ Importantly, the entire upgrade process—including migrating the ETH to the `S Note that migration processes may not be uniform and may vary according to the status of the chain seeking to join the OP-governed interoperable set. As stated in the previous section, chains are expected to ensure they reach the approved, OP Stack version. In practice, different migration paths could be implemented, for example, to allow chains to use the `SharedLockbox` from inception or migrate from a previous one, for example. +```mermaid +sequenceDiagram + participant L1PAO as L1 ProxyAdmin Owner + participant ProxyAdmin as ProxyAdmin + participant SystemConfigProxy as SystemConfig + participant StorageSetter + participant SuperchainConfig + participant OptimismPortalProxy as OptimismPortal + participant LiquidityMigrator + participant SharedLockbox + + Note over L1PAO: Start batch + + %% Step 1: Upgrade SystemConfig to StorageSetter to zero out initialized slot + L1PAO->>ProxyAdmin: upgradeAndCall() + ProxyAdmin->>SystemConfigProxy: Upgrade to StorageSetter + SystemConfigProxy->>StorageSetter: Call to set initialized slot to zero + + %% Step 2: Upgrade SystemConfig and initialize with SuperchainConfig + L1PAO->>ProxyAdmin: upgradeAndCall() + ProxyAdmin->>SystemConfigProxy: Upgrade to new SystemConfig implementation + ProxyAdmin->>SystemConfigProxy: Call initialize(...SuperchainConfig address) + + %% Step 3: Add chain to SuperchainConfig + L1PAO->>SuperchainConfig: addChain(chainId, SystemConfig address) + + %% Step 4: Upgrade OptimismPortal to intermediate implementation that transfers ETH + L1PAO->>ProxyAdmin: upgradeAndCall() + ProxyAdmin->>OptimismPortalProxy: Upgrade to LiquidityMigrator + OptimismPortalProxy->>LiquidityMigrator: Call migrateETH() + OptimismPortalProxy->>SharedLockbox: Transfer entire ETH balance + + %% Step 5: Upgrade OptimismPortal to final implementation + L1PAO->>ProxyAdmin: upgrade() + ProxyAdmin->>OptimismPortalProxy: Upgrade to new OptimismPortal implementation + + Note over L1PAO: End batch +``` + ## Impact The following components require an audit of the new and modified contracts: `OptimismPortal`, `SharedLockbox`, and `SuperchainConfig`. This also includes the scripts necessary to perform the migration. From d2e4a6478c86ad1b2a3f9f90a07fc22ff7af6503 Mon Sep 17 00:00:00 2001 From: AgusDuha <81362284+agusduha@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:51:54 -0300 Subject: [PATCH 10/10] fix: remove dependency manager (#3) --- protocol/eth-shared-lockbox.md | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/protocol/eth-shared-lockbox.md b/protocol/eth-shared-lockbox.md index 9b35ec2f..47be9384 100644 --- a/protocol/eth-shared-lockbox.md +++ b/protocol/eth-shared-lockbox.md @@ -1,6 +1,6 @@ # Purpose -*The document presented below is part of the [Interoperability project](https://github.com/orgs/ethereum-optimism/projects/71/views/1?sliceBy%5Bvalue%5D=skeletor-spaceman).* +_The document presented below is part of the [Interoperability project](https://github.com/orgs/ethereum-optimism/projects/71/views/1?sliceBy%5Bvalue%5D=skeletor-spaceman)._ This document discusses possible solutions to address the constraints on ETH withdrawals resulting from the introduction of interop and `SuperchainWETH` that share ETH liquidity across a set of interoperable OP Chains. @@ -30,7 +30,7 @@ OP Chains will be governed within a common Chain Cluster governance entity (the - **Ensuring chains are consistent at the implementation side**, achieved either through trusted deployment methods (e.g., OP Contracts Manager) or by approval after security checks are performed. - **Approving protocol upgrades** for all chains involved. -- **Adding new chains** to the interoperable set, and managing the `dependencyManager` role. The final decision is up to governance and chains cannot be removed afterwards. +- **Adding new chains** to the interoperable set. The final decision is up to governance and chains cannot be removed afterwards. - **Replacing chain servicers** for existing chains if they fail to satisfy technical requirements. ### Shared Bridging and SuperchainWETH usage @@ -42,14 +42,16 @@ In any OP Chain that joins the cluster, it is assumed that `SuperchainWETH` ha The existing problem and considerations motivate us to propose an L1 shared liquidity design through the introduction of a new `SharedLockbox` on L1, which serves as a singleton contract for ETH, given a defined set of interoperable chains. To ensure consistency, the `SuperchainConfig` is extended to act as the *dependency set manager*, controlling the op-governed dependency set that the lockbox uses as a source of truth. New ETH deposits will be directed to the lockbox, with the same process applied to ETH withdrawals. ### Spec changes + The core proposed changes are as follows: -- **Modify the `SuperchainConfig` contract**: Extend this contract to manage the dependency set of each chain, taking ownership of the `dependencyManager` role for each `SystemConfig`. + +- **Modify the `SuperchainConfig` contract**: Extend this contract to manage the dependency set of each chain, interacting with each `SystemConfig`. - **Introduce the `SharedLockbox` contract**: This contract acts as an escrow for ETH, receiving deposits and allowing withdrawals from approved `OptimismPortal` contracts. The `SuperchainConfig` contract serves as the source of truth of the lockbox. - **Modify the `OptimismPortal`**: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the inverse process applying when `finalizeWithdrawal` is called. ### Managing op-governed dependency set through `SuperchainConfig` -The `SuperchainConfig` contract will serve as the single point for managing the dependency set of a cluster and will be managed by the admin as occurs in other L1 OP contracts. This contract assumes the role of `dependencyManager` for every `SystemConfig` contract involved. Since the dependency graph follows a simple dependency, it only stores a mapping (or array) of chains added, e.g. given a `chainId`. +The `SuperchainConfig` contract will serve as the single point for managing the dependency set of a cluster and will be managed by the admin as occurs in other L1 OP contracts. This contract interacts with every `SystemConfig` contract involved. Since the dependency graph follows a simple dependency, it only stores a mapping (or array) of chains added, e.g. given a `chainId`. ```solidity // Mapping from chainId to SystemConfig address @@ -126,8 +128,6 @@ Note that migration processes may not be uniform and may vary according to the s sequenceDiagram participant L1PAO as L1 ProxyAdmin Owner participant ProxyAdmin as ProxyAdmin - participant SystemConfigProxy as SystemConfig - participant StorageSetter participant SuperchainConfig participant OptimismPortalProxy as OptimismPortal participant LiquidityMigrator @@ -135,26 +135,16 @@ sequenceDiagram Note over L1PAO: Start batch - %% Step 1: Upgrade SystemConfig to StorageSetter to zero out initialized slot - L1PAO->>ProxyAdmin: upgradeAndCall() - ProxyAdmin->>SystemConfigProxy: Upgrade to StorageSetter - SystemConfigProxy->>StorageSetter: Call to set initialized slot to zero - - %% Step 2: Upgrade SystemConfig and initialize with SuperchainConfig - L1PAO->>ProxyAdmin: upgradeAndCall() - ProxyAdmin->>SystemConfigProxy: Upgrade to new SystemConfig implementation - ProxyAdmin->>SystemConfigProxy: Call initialize(...SuperchainConfig address) - - %% Step 3: Add chain to SuperchainConfig + %% Step 1: Add chain to SuperchainConfig L1PAO->>SuperchainConfig: addChain(chainId, SystemConfig address) - %% Step 4: Upgrade OptimismPortal to intermediate implementation that transfers ETH + %% Step 2: Upgrade OptimismPortal to intermediate implementation that transfers ETH L1PAO->>ProxyAdmin: upgradeAndCall() ProxyAdmin->>OptimismPortalProxy: Upgrade to LiquidityMigrator OptimismPortalProxy->>LiquidityMigrator: Call migrateETH() OptimismPortalProxy->>SharedLockbox: Transfer entire ETH balance - %% Step 5: Upgrade OptimismPortal to final implementation + %% Step 3: Upgrade OptimismPortal to final implementation L1PAO->>ProxyAdmin: upgrade() ProxyAdmin->>OptimismPortalProxy: Upgrade to new OptimismPortal implementation @@ -177,13 +167,12 @@ The problem with L2 reverts is that it breaks the ETH withdrawal guarantee invar ### **Permission to withdraw ETH from a different Portal** -[Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if we have a dependency set composed by Chain A, B and C, a withdrawal initiated from A could be finalized by using funds from B and C if needed. +[Another solution](https://github.com/ethereum-optimism/specs/issues/362#issuecomment-2332481041) involves allowing ETH withdrawals to be finalized by taking ETH from one or more `OptimismPortal` contracts. In a cluster, this is done by authorizing withdrawals across the set of chains. For example, if we have a dependency set composed by Chain A, B and C, a withdrawal initiated from A could be finalized by using funds from B and C if needed. The implementation would require iterating through the dependency set, determined on L1 to find the next `OptimismPortal` with available funds. This also means `OptimismPortal` would need to have authorization and validation logic to allow to extraction ETH given an arbitrary request dictated by the loop. **Implementation and security considerations** Since both approaches rely on multiple `OptimismPortal` contracts and access controls, the Shared Lockbox design stays as the minimal way to implement a shared liquidity approach. Instead, allowing a looping withdrawal into each `OptimismPortal` increases the code complexity and surface of bugs during the iterative checking. - # Risks & Uncertainties - **Scalable security**: With interop, withdrawals are a critical flow to protect, especially for ETH, since it tentatively becomes the most bridged asset across the Superchain. This means proof systems, dedicated monitoring services, the Security Council, and the Guardian need to be proven to tolerate the growing number of chains.