Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add shared lockbox spec #465

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions specs/interop/dependency-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,8 @@ It is a known issue that not all software in the Ethereum can handle 32 byte cha

## Updating the Dependency Set

The `SystemConfig` is updated to manage a new role, `dependencyManager`.
It can only updated by the `ProxyAdmin` during an contract upgrade.
The sole holder of this role is the only address
permissioned to update (remove/add to) the dependency set of that chain.

The `SystemConfig` is also updated to manage the dependency set.
The address with the `dependency manager` role can add or remove
chains from the dependency set through the `SystemConfig`.

The `SystemConfig` MUST enforce that the maximum size of the dependency set is `type(uint8).max` or 255.
The `SuperchainConfig` is updated to manage the dependency set.
More details can be found on the [dependency manager section](./../protocol/superchain-configuration.md#dependency-manager).

## Security Considerations

Expand Down
77 changes: 77 additions & 0 deletions specs/interop/optimism-portal-interop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# OptimismPortal

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [Overview](#overview)
- [Integrating `SharedLockbox`](#integrating-sharedlockbox)
- [`depositTransaction`](#deposittransaction)
- [`finalizeWithdrawalTransactionExternalProof`](#finalizewithdrawaltransactionexternalproof)
- [Invariants](#invariants)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be clear that its possible to upgrade to this hardfork and not be part of a cluster. The requirement would be that a chain has its own lockbox


The `OptimismPortal` contract is upgraded to integrate the `SharedLockbox` and start using the shared ETH liquidity.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"using the shared ETH liquidity" is a bit ambiguous imo, as each OptimismPortal is practically storing its Ether in the shared lock box, so we should note that funds are being moved with this change

This liquidity consists of every ETH balance migrated from each `OptimismPortal`
when joining the op-governed dependency set.

It is possible to upgrade to this version without being part of the op-governed dependency set. In this case,
the corresponding chain would need to deploy and manage its own `SharedLockbox` and `SuperchainConfig`.

### Integrating `SharedLockbox`

The integration with the `SharedLockbox` involves locking ETH when executing deposit transactions and unlocking ETH
when finalizing withdrawal transactions, without altering other aspects of the current `OptimismPortal` implementation.

To implement this solution, the following changes are needed:

#### `depositTransaction`

Calls `lockETH` on the `SharedLockbox` with the `msg.value`.

- The function MUST call `lockETH` with `msg.value` on the `SharedLockbox` if:
- The token is `ETHER`.
- `msg.value` is greater than zero.

```mermaid
sequenceDiagram
participant User
participant OptimismPortal
participant SharedLockbox

User->>OptimismPortal: depositTransaction(...)
OptimismPortal->>SharedLockbox: lockETH()
OptimismPortal->>OptimismPortal: emit TransactionDeposited()
```

#### `finalizeWithdrawalTransactionExternalProof`

Calls `unlockETH` on the `SharedLockbox` with the `tx.value`.

- The function MUST call `unlockETH` on the `SharedLockbox` if:
- The token is `ETHER`.
- `tx.value` is greater than zero.
- The ETH is received by the `OptimismPortal` and then sent with the withdrawal transaction

```mermaid
sequenceDiagram
participant User
participant OptimismPortal
participant SharedLockbox

User->>OptimismPortal: finalizeWithdrawalTransactionExternalProof(...)
OptimismPortal->>SharedLockbox: unlockETH(uint256 value)
SharedLockbox->>OptimismPortal: donateETH()
OptimismPortal->>OptimismPortal: emit WithdrawalFinalized()
```

### Invariants

- It MUST lock the ETH amount on the `SharedLockbox` when on a deposit transaction with value greater than zero

- It MUST unlock the ETH amount being withdrawn from the `SharedLockbox` if it is greater than zero

- It MUST NOT hold any ETH balance from any deposit transaction.
31 changes: 7 additions & 24 deletions specs/interop/predeploys.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
- [Overview](#overview-2)
- [L1Block](#l1block)
- [Static Configuration](#static-configuration)
- [Dependency Set](#dependency-set)
- [Deposit Context](#deposit-context)
- [`isDeposit()`](#isdeposit)
- [`depositsComplete()`](#depositscomplete)
Expand Down Expand Up @@ -128,10 +127,10 @@ Emits the `ExecutingMessage` event to signal the transaction has a cross chain m

The following fields are required for validating a cross chain message:

| Name | Type | Description |
| -------- | ---------- | -------------------------------------------------------------------------- |
| `_id` | Identifier | A [`Identifier`] pointing to the initiating message. |
| `_msgHash` | `bytes32` | The keccak256 hash of the message payload matching the initiating message. |
| Name | Type | Description |
| ---------- | ---------- | -------------------------------------------------------------------------- |
| `_id` | Identifier | A [`Identifier`] pointing to the initiating message. |
| `_msgHash` | `bytes32` | The keccak256 hash of the message payload matching the initiating message. |

```solidity
validateMessage(Identifier calldata _id, bytes32 _msgHash)
Expand Down Expand Up @@ -656,22 +655,6 @@ where

Calls to `setConfig` MUST originate from `SystemConfig` and are forwarded to `L1Block` by `OptimismPortal`.

### Dependency Set

`L1Block` is updated to include the set of allowed chains. These chains are added and removed through `setConfig` calls
with `ADD_DEPENDENCY` or `REMOVE_DEPENDENCY`, respectively. The maximum size of the dependency set is `type(uint8).max`,
and adding a chain id when the dependency set size is at its maximum MUST revert. If a chain id already in the
dependency set, such as the chain's chain id, is attempted to be added, the call MUST revert. If a chain id that is not
in the dependency set is attempted to be removed, the call MUST revert. If the chain's chain id is attempted to be
removed, the call also MUST revert.

`L1Block` MUST provide a public getter to check if a particular chain is in the dependency set called
`isInDependencySet(uint256)`. This function MUST return true when a chain id in the dependency set, or the chain's chain
id, is passed in as an argument, and false otherwise. Additionally, `L1Block` MUST provide a public getter to return the
dependency set called `dependencySet()`. This function MUST return the array of chain ids that are in the dependency set.
`L1Block` MUST also provide a public getter to get the dependency set size called `dependencySetSize()`. This function
MUST return the length of the dependency set array.

### Deposit Context

New methods will be added on the `L1Block` contract to interact with [deposit contexts](./derivation.md#deposit-context).
Expand Down Expand Up @@ -954,9 +937,9 @@ sequenceDiagram
L2SBA->>SuperERC20_A: crosschainBurn(from, amount)
SuperERC20_A-->SuperERC20_A: emit CrosschainBurn(from, amount)
L2SBA->>Messenger_A: sendMessage(chainId, message)
Messenger_A->>L2SBA: return msgHash_
Messenger_A->>L2SBA: return msgHash_
L2SBA-->L2SBA: emit SentERC20(tokenAddr, from, to, amount, destination)
L2SBA->>from: return msgHash_
L2SBA->>from: return msgHash_
Inbox->>Messenger_B: relayMessage()
Messenger_B->>L2SBB: relayERC20(tokenAddr, from, to, amount)
L2SBB->>SuperERC20_B: crosschainMint(to, amount)
Expand Down Expand Up @@ -987,7 +970,7 @@ The bridging of `SuperchainERC20` using the `SuperchainERC20Bridge` will require
to the same address on the target chain.
Similarly, the `relayERC20()` function should only process messages originating from the same address.
- Note: The [`Create2Deployer` preinstall](../protocol/preinstalls.md#create2deployer)
and the custom Factory will ensure same address deployment.
and the custom Factory will ensure same address deployment.
- Locally initiated: The bridging action should be initialized
from the chain where funds are located only.
- This is because the same address might correspond to different users cross-chain.
Expand Down
127 changes: 127 additions & 0 deletions specs/interop/shared-lockbox-upgrade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Shared Lockbox - Upgrade and migration process

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [Overview](#overview)
- [Add dependency to the op-governed dependency set in `SuperchainConfig`](#add-dependency-to-the-op-governed-dependency-set-in-superchainconfig)
- [Migrate ETH liquidity from `OptimismPortal` to `SharedLockbox`](#migrate-eth-liquidity-from-optimismportal-to-sharedlockbox)
- [`LiquidityMigrator`](#liquiditymigrator)
- [`OptimismPortal` code upgrade](#optimismportal-code-upgrade)
- [Batch transaction process](#batch-transaction-process)
- [Diagram](#diagram)
- [Future Considerations / Additional Notes](#future-considerations--additional-notes)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

Based on the assumption that a chain joining the op-governed dependency set is an irreversible process,
it is assumed that joining the Shared Lockbox is equivalent to it.

The upgrade process consists of three main points:

- Add dependency to the op-governed dependency set in `SuperchainConfig`
- Move ETH liquidity from `OptimismPortal` to `SharedLockbox`
- Upgrade the code of `OptimismPortal` to include the `SharedLockbox` integration

This process also requires that:

- `SharedLockbox` is deployed
- `LiquidityMigrator` is deployed
- `SuperchainConfig` is upgraded to manage the dependency set

### Add dependency to the op-governed dependency set in `SuperchainConfig`

The `SuperchainConfig` contract will be responsible for storing and managing the dependency set.
Its `addDependency` function will be used to add the chain ID to the dependency set.
It will also allowlist the corresponding `OptimismPortal`, enabling it to lock and unlock ETH from the `SharedLockbox`.

### Migrate ETH liquidity from `OptimismPortal` to `SharedLockbox`

The ETH will be transferred from the `OptimismPortal` to the `SharedLockbox` using the `LiquidityMigrator` contract.
This contract functions similarly to upgrades using the `StorageSetter`, being updated immediately before to the real implementation.
Its sole purpose is to transfer the ETH balance.
This approach eliminates the need for adding code to move the liquidity to the lockbox that won't be used again.

#### `LiquidityMigrator`

This contract is meant to be used as an intermediate step for the liquidity migration.
Its unique purpose is to transfer the whole ETH balance from `OptimismPortal` to `SharedLockbox`.
This approach avoids adding extra code to the `initialize` function, which could be prone to errors in future updates.

**Interface and properties**

**`migrateETH`**

Transfers the entire ETH balance from the `OptimismPortal` to the `SharedLockbox`.

```solidity
function migrateETH() external;
```

**Invariants**

- It MUST migrate the whole `OptimismPortal` ETH balance to the `SharedLockbox`

- It MUST emit `ETHMigrated` when migrating the balance

### `OptimismPortal` code upgrade

The `OptimismPortal` will start locking and unlocking ETH through the `SharedLockbox`.
It will continue to handle deposits and withdrawals but won't directly hold the ETH liquidity.
To set this up, the upgrade function will be called via `ProxyAdmin` to implement the new code,
which includes the necessary `SharedLockbox` integration.

## Batch transaction process

The approach consists of handling the entire migration process in a single batched transaction.
This transaction will include:

1. Call `addDependency` in the `SuperchainConfig`
- Sending chain ID + system config address
2. Call `upgradeAndCall` in the `ProxyAdmin` for the `OptimismPortal`
- Update provisionally to the `LiquidityMigrator` to transfer the whole ETH balance to the `SharedLockbox` in this call.
3. Call `upgrade` in the `ProxyAdmin` for the `OptimismPortal`
- The `SharedLockbox` address is set as immutable in the new implementation

The L1 ProxyAdmin owner (L1PAO) will execute this transaction. As the entity responsible for updating contracts,
it has the authority to perform the second and third steps.
For the first step, the L1PAO has to be set as authorized for adding a dependency to the op-governed dependency set
on the `SuperchainConfig` when initializing.
This process can be set as a [superchain-ops](https://github.com/ethereum-optimism/superchain-ops) task.

### Diagram

```mermaid
sequenceDiagram
participant L1PAO as L1 ProxyAdmin Owner
participant ProxyAdmin as ProxyAdmin
participant SuperchainConfig
participant OptimismPortalProxy as OptimismPortal
participant LiquidityMigrator
participant SharedLockbox

Note over L1PAO: Start batch

%% Step 1: Add dependency to SuperchainConfig
L1PAO->>SuperchainConfig: addDependency(chainId, SystemConfig address)
SuperchainConfig->>SharedLockbox: authorizePortal(OptimismPortal address)

%% 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 3: Upgrade OptimismPortal to final implementation
L1PAO->>ProxyAdmin: upgrade()
ProxyAdmin->>OptimismPortalProxy: Upgrade to new OptimismPortal implementation

Note over L1PAO: End batch
```

## Future Considerations / Additional Notes

- Before calling `addDependency`, it MUST be ensured that the `chainId` and `systemConfig` match
Loading