Skip to content

Commit ad88bd6

Browse files
authored
feat: ETH lockbox redesign (#206)
* feat: ETH lockbox redesign * fix: proxy admin owner role * fix: pr fixes * fix: add proxy admin owner check
1 parent 474e956 commit ad88bd6

File tree

1 file changed

+44
-90
lines changed

1 file changed

+44
-90
lines changed

protocol/eth-shared-lockbox.md

Lines changed: 44 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This document discusses possible solutions to address the constraints on ETH wit
66

77
# Summary
88

9-
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.
9+
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 `ETHLockbox`, which is considered the most effective solution.
1010

1111
# Problem Statement + Context
1212

@@ -35,125 +35,82 @@ OP Chains will be governed within a common Chain Cluster governance entity (the
3535

3636
### Shared Bridging and SuperchainWETH usage
3737

38-
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.
38+
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.
3939

4040
# Solution
4141

42-
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.
42+
The existing problem and considerations motivate us to propose an L1 shared liquidity design through the introduction of a new `ETHLockbox` on L1, which serves as a singleton contract for ETH, given a defined set of interoperable chains. New ETH deposits will be directed to the lockbox, with the same process applied to ETH withdrawals.
4343

4444
### Spec changes
4545

4646
The core proposed changes are as follows:
4747

48-
- **Modify the `SuperchainConfig` contract**: Extend this contract to manage the dependency set of each chain, interacting with each `SystemConfig`.
49-
- **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.
50-
- **Modify the `OptimismPortal`**: To forward ETH into the `SharedLockbox` when `depositTransaction` is called, with the inverse process applying when `finalizeWithdrawal` is called.
48+
- **Introduce the `ETHLockbox` contract**: This contract acts as an escrow for ETH, receiving deposits and allowing withdrawals from approved `OptimismPortal` contracts. It is proxied and owned by the L1 `ProxyAdmin` contract.
49+
- **Modify the `OptimismPortal`**: To forward ETH into the `ETHLockbox` when `depositTransaction` is called, with the inverse process applying when `finalizeWithdrawal` is called.
5150

52-
### Managing op-governed dependency set through `SuperchainConfig`
51+
### `ETHLockbox` implementation
5352

54-
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`.
55-
56-
```solidity
57-
// Mapping from chainId to SystemConfig address
58-
mapping(uint256 _chainId => ISystemConfig) public systemConfigs;
59-
60-
// Current dependency set list
61-
EnumerableSet.UintSet private _dependencySet;
62-
```
63-
64-
Adding a new chain can be done by introducing a new function called `addChain`. The process would look as follows:
65-
66-
1. The `updater` calls the function with `chainId` and `SystemConfig`.
67-
2. An external call is made to each `SystemConfig` from already added chains with the new `chainId`.
68-
3. The new `SystemConfig` is called to add all previously existing `chainId` from `SuperchainConfig` to itself.
69-
4. Each call concludes by emitting a `DepositedTransaction` event.
70-
5. The `OptimismPortal` address is stored in the `Sharedlockbox` mapping.
71-
6. Each chain asynchronously includes each new deposit and updates `dependencySet` in `L1Block`.
72-
73-
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.
74-
75-
A code example would look like this:
53+
A minimal set of functions should include:
7654

77-
```solidity
78-
function addChain(uint256 _chainId, address _systemConfig) external {
79-
require(msg.sender == updater(), "Unauthorized");
80-
// Add to the dependency set and check it is not already added (`add()` returns false if it already exists)
81-
require(_dependencySet.add(_chainId), "Chain already added");
55+
- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal`.
56+
- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal`.
8257

83-
// Store the system config
84-
systemConfigs[_chainId] = _systemConfig;
58+
Access control for `lockETH` and `unlockETH` is validated against the mapping of authorized `OptimismPortal` addresses.
8559

86-
// Loop through the dependency set and update the dependency for each chain
87-
for (uint256 i; i < _dependencySet.length() - 1; i++) {
60+
The `ProxyAdmin` owner can add `OptimismPortal` addresses to the `ETHLockbox` contract. This role can be introspected in the `ETHLockbox` contract.
8861

89-
uint256 currentId = _dependencySet.at(i);
62+
### `OptimismPortal` upgrade process
9063

91-
// Skip recently added chain
92-
if (_chainId == currentId) continue;
64+
A ETH migration function can be added to the `OptimismPortal` to allow transferring all ETH to the `ETHLockbox` at any time. The `ETHLockbox` address is set during initialization of the `OptimismPortal` and cannot be changed afterwards.
9365

94-
systemConfigs[currentId].addDependency(_chainId);
66+
The migration process would work as follows:
9567

96-
systemConfigs[_chainId].addDependency(currentId);
97-
}
68+
- Only the `ProxyAdmin` owner can trigger the migration
69+
- The `OptimismPortal` MUST be first authorized in the `ETHLockbox`
70+
- Transfer the entire ETH balance of the `OptimismPortal` to the pre-configured `ETHLockbox`
9871

99-
address portal = _systemConfig.optimismPortal();
72+
### `ETHLockbox` merge process
10073

101-
// Authorize the portal on the shared lockbox
102-
SHARED_LOCKBOX.authorizePortal(portal);
74+
The `ETHLockbox` includes a migration function to allow transferring all ETH to another existing lockbox. This enables merging liquidity pools by migrating ETH from one lockbox to another, allowing multiple portals to use the same shared liquidity.
10375

104-
emit ChainAdded(_chainId, _systemConfig, portal);
105-
}
106-
```
76+
The merge process has two parts:
10777

108-
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.
78+
1. Destination lockbox preparation:
10979

110-
### `SharedLockbox` implementation
80+
- Only the `ProxyAdmin` owner can approve a specific source lockbox to send ETH
81+
- This prevents receiving ETH from unauthorized or incorrect lockboxes
11182

112-
A minimal set of functions should include:
83+
2. Source lockbox migration:
11384

114-
- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal`.
115-
- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal`.
85+
- Only the `ProxyAdmin` owner can trigger the migration
86+
- The destination lockbox is provided as a parameter during migration
87+
- The `ProxyAdmin` owner of the source lockbox must be the same as the `ProxyAdmin` owner of the destination lockbox
88+
- Transfer the entire ETH balance to the specified destination lockbox
89+
- After migration, the source lockbox will no longer be used by any `OptimismPortal`
11690

117-
Access control for `lockETH` and `unlockETH` is validated against the mapping of authorized `OptimismPortal` addresses.
91+
This ensures a secure way to consolidate ETH liquidity from multiple lockboxes into a single one. After migration, the portal previously using the source lockbox would need to be updated to point to the destination lockbox.
11892

119-
### `OptimismPortal` upgrade process
93+
## Diagram
12094

121-
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.
95+
```mermaid
96+
flowchart TD
97+
SuperchainConfig ~~~ OptimismPortal --> SuperchainConfig
98+
OptimismPortal ~~~ SuperchainConfig
12299
123-
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.
100+
SuperchainConfig ~~~ OptimismPortal' --> SuperchainConfig
101+
OptimismPortal' ~~~ SuperchainConfig
124102
125-
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.
103+
SuperchainConfig ~~~ OptimismPortal'' --> SuperchainConfig
104+
OptimismPortal'' ~~~ SuperchainConfig
126105
127-
```mermaid
128-
sequenceDiagram
129-
participant L1PAO as L1 ProxyAdmin Owner
130-
participant ProxyAdmin as ProxyAdmin
131-
participant SuperchainConfig
132-
participant OptimismPortalProxy as OptimismPortal
133-
participant LiquidityMigrator
134-
participant SharedLockbox
135-
136-
Note over L1PAO: Start batch
137-
138-
%% Step 1: Add chain to SuperchainConfig
139-
L1PAO->>SuperchainConfig: addChain(chainId, SystemConfig address)
140-
141-
%% Step 2: Upgrade OptimismPortal to intermediate implementation that transfers ETH
142-
L1PAO->>ProxyAdmin: upgradeAndCall()
143-
ProxyAdmin->>OptimismPortalProxy: Upgrade to LiquidityMigrator
144-
OptimismPortalProxy->>LiquidityMigrator: Call migrateETH()
145-
OptimismPortalProxy->>SharedLockbox: Transfer entire ETH balance
146-
147-
%% Step 3: Upgrade OptimismPortal to final implementation
148-
L1PAO->>ProxyAdmin: upgrade()
149-
ProxyAdmin->>OptimismPortalProxy: Upgrade to new OptimismPortal implementation
150-
151-
Note over L1PAO: End batch
106+
OptimismPortal --> ETHLockbox
107+
OptimismPortal' --> ETHLockbox'
108+
OptimismPortal'' --> ETHLockbox'
152109
```
153110

154111
## Impact
155112

156-
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.
113+
The following components require an audit of the new and modified contracts: `OptimismPortal` and `ETHLockbox`.
157114

158115
# Alternatives Considered
159116

@@ -169,13 +126,10 @@ The problem with L2 reverts is that it breaks the ETH withdrawal guarantee invar
169126

170127
[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.
171128

172-
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.
129+
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.
173130
**Implementation and security considerations**
174131
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.
175132

176133
# Risks & Uncertainties
177134

178135
- **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.
179-
- **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`.
180-
- **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.
181-
- **`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.

0 commit comments

Comments
 (0)