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

interop: add Dependency Set Manager & Shared Lockbox design doc #84

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Joxess
Copy link
Contributor

@Joxess Joxess commented Sep 18, 2024

Co-authored-by: ng [email protected]

Description

The following design doc cover a previous discussed issue on ETH withdrawals introduced by interop. The Shared lockbox is presented as the most convenient solution to solve this problem. However, it is known that the design also is the interest for various aspects of the Superchain design, such as chain management, core interop, and others, which need to be carefully discussed.

Additional context

This doesn't address the case for L1 bridged tokens.

@K-Ho
Copy link

K-Ho commented Sep 20, 2024

From a product perspective - the ETH shared lockbox design solves a lot of user pain, by maintaining the invariant that "any amount of ETH can always be withdrawn from L2 to L1 safely", which many protocols have built upon. I think the only concern at this point is the time and resources required to actually ship this securely. Is there some rough scoping of the amount of time this adds to the engineering timeline for interoperable ETH? Who would we need review/support from to feel confident in the security of this upgrade? It's certainly a major change and would want to make sure we get a diverse set of reviews/eyes on this + put together a very thorough Failure Mode Analysis

@K-Ho
Copy link

K-Ho commented Sep 20, 2024

Also a stream of work will be making sure that external tooling that relies on the OptimismPortal to calculate ETH stored in a chain is updated as well (e.g. update L2Beat, Defillama, etc.)

@Joxess
Copy link
Contributor Author

Joxess commented Sep 20, 2024

Also a stream of work will be making sure that external tooling that relies on the OptimismPortal to calculate ETH stored in a chain is updated as well (e.g. update L2Beat, Defillama, etc.)

This is a very interesting consideration. Actually, when making ETH interoperable, a shift in the interpretation of liquidity distribution is needed. To show the actual TVL, OptimismPortal isn't the only data to reference anymore; it is also necessary to consider the new contributions whenever ETH enters or exits in the form of SuperchainWETH. Probably, similar reasoning as in the case of a migration (deposit mapping + SuperchainWETH net flows) will need to be followed.

protocol/eth-shared-lockbox.md Outdated Show resolved Hide resolved
protocol/eth-shared-lockbox.md Outdated Show resolved Hide resolved
protocol/eth-shared-lockbox.md Outdated Show resolved Hide resolved
protocol/eth-shared-lockbox.md Outdated Show resolved Hide resolved
protocol/eth-shared-lockbox.md Show resolved Hide resolved

# 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.
Copy link
Contributor

@Ethnical Ethnical Sep 27, 2024

Choose a reason for hiding this comment

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

in L1 that serves as a singleton ETH contract

So every interop chains are about to forward ETH into theSharedLockbox so we should be capable to track the amount of total ETH on the Superchain by checking the balance of this contract?
Or there is still chains that will keep ETH in the previous OptimismPortal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question. In this design, chains that are part of the interoperable graph must adhere to the SharedLockbox by default, so the total amount of ETH will be there. Although, in principle, one could design this solution as opt-in, it could revert to the main problem and still make them susceptible to liquidity constraints.

@Joxess Joxess changed the title interop: add ETH Shared Lockbox design doc interop: add Dependency Set Manager & Shared Lockbox design doc Oct 30, 2024
@Joxess
Copy link
Contributor Author

Joxess commented Oct 30, 2024

I have updated the doc with substantial changes:

  • Updates to the Considerations section
  • Introduction of the DependencySetManager contract as a replacement for the old "Joining the Cluster" section
  • Proposed changes to SystemConfigInterop
  • Modifications to the upgrade process
  • Removal of the "Opt-out of the Cluster" section and liquidity trackability features


### Shared Security Model

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.).
Copy link
Contributor

Choose a reason for hiding this comment

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

It sounds like this means we will have to move the respected game type out of the portal, where it can be different per-chain, and into the SuperchainConfig, where it's the same for all chains?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I believe that this is required given that there is an idea of shared security between all of the chains

Copy link
Contributor

Choose a reason for hiding this comment

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

RespectedGameType is already being moved into AnchorStateRegistry which may begin to resolve this problem

Copy link
Contributor

Choose a reason for hiding this comment

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

At first thought, we are going to need to have the RespectedGameType be the same for all interoperable chains, otherwise we risk heterogeneous (weakest link) security, so it may need to move again, or we will need to use social consensus to make sure all the values are the same and have playbooks for modifying them all atomically. Doable at a small number of chains, but definitely not ideal, so I do think it makes sense to put it in the SuperchainRegistry given the AnchorStateRegistry will have its own proxy for each chain


### Unified Chain Governance

OP Chains will be governed within a common Chain Cluster governance entity (the Collective). Currently, this entity is responsible for:
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this just the standard existing governance process, or is this something new?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is based in a recent draft on op-governed interop set

Choose a reason for hiding this comment

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

We expect this to be the standard existing governance process, as outlined here: https://docs.google.com/document/d/1zeDO241CHl1H8Xl3XqdkmMedP4KQwT4AMRJQ32Hs_HE/edit

- **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.
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the implications? Can chains be removed from the interoperable set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above

Copy link

@zainbacchus zainbacchus Nov 4, 2024

Choose a reason for hiding this comment

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

Chains should not be able to removed, a sequencer could.
"Once a chain is added to the OP-governed interop set it cannot be removed.

A chain servicer (not chain) can be replaced from the OP-governed interop set for failing to satisfy the technical requirements..."

https://docs.google.com/document/d/1zeDO241CHl1H8Xl3XqdkmMedP4KQwT4AMRJQ32Hs_HE/edit


### 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean that it's "activated", how does this occur at the same time as updating the dependency set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This means that we assume when a chain receives the interop upgrade (and then joins the dependency set), SuperchainWETH will also be deployed

Copy link
Contributor

Choose a reason for hiding this comment

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

Why limit SuperchainWETH to being part of the cluster? It seems exclusive, the contract should always just exist on any chain post interop hardfork being activated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's ok; it should not be a problem


# 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this lockbox only for ETH, and not tokens? Don't tokens have the same withdrawal liquidity problem when moved between chains?

Copy link
Contributor

Choose a reason for hiding this comment

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

The idea is to keep the scope small for now

Choose a reason for hiding this comment

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

ETH is the priority for the initial release.

We do expect to come back to deposited tokens but not for the inital release to limit scope.


### 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`.
Copy link
Contributor

Choose a reason for hiding this comment

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

In the case of a simple dependency

What does this mean, and what is the other case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, not the best phrasing; we’re assuming a simple dependency only

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.
2. An OP-governed address, who has the role to call `addChain` with the new `chainId`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to store the dependency set twice, in the shared DependencySetManager / OPCM source of truth (unsure which it is from the text), and again in the system configs?

Copy link

Choose a reason for hiding this comment

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

This has been already discussed on the Design Review call:
There is no dependency set within SystemConfig; it simply sends the added dependency to L2 to maintain synchronization. Because of this, Matt was ok with the approach presented.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would be in favor of adding the dependency set to the L1 system config to be honest, no need to do so but its about keeping a symmetrical API per chain, since the data is available on L2


// Function to add a chain to the dependency set
function addChain(uint256 chainId) external onlyOwner {
require(systemConfigInterops[chainId] != address(0), "DependencySetManager: Chain not registered");
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, indentation looks right in the code block text, but off when rendered
image

- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal2`.
- `unlockETH`: Releases ETH from the `finalizeWithdrawalTransaction` originating from a valid `OptimismPortal2`.

Access control for `lockETH` and `unlockETH` is validated against the list reated by `registerChain`.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo, "reated"


### `OptimismPortal2` 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.
Copy link
Contributor

@mds1 mds1 Nov 1, 2024

Choose a reason for hiding this comment

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

What alternative migration flows have we considered and what are the tradeoffs? For example, we could just add a forwardETH() method to the portals that forwards all ETH balance to the lockbox whenever it's called, and call it from the initialize function. (We wouldn't want this forwardETH method callable for chains not in the interop set so it'd have to check for that and revert accordingly)

Copy link

Choose a reason for hiding this comment

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

We are exploring various migration options, with the goal of minimizing the amount of permanently added code. We’ll share some insights on this soon.

Comment on lines 48 to 49
- 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

What alternatives are there to adding these two contracts? For example, can the functionality of the DependencySetManager instead live in SuperchainConfig or OPCM?

My main concern is that we have a lot of L1 contracts already so our architecture + auth can be confusing. I'd like to work towards reducing the number of contracts (when it makes sense to, i.e. good separation of concerns is still important). But both SuperchainConfig and OPCM feel like suitable candidates for the role of DependencySetManager

Copy link
Contributor

Choose a reason for hiding this comment

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

A way to think about this is that there is a difference from the ways that the protocol may work, and the way that we want to the protocol to work. Right now we want to enforce a bidirectional relationship for all dependencies. Whatever contract is the dependencyManager role should enforce this

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not opinionated on what contract does this enforcement, whether its the SuperchainConfig or not, we should inspect where the roles live and come to a shared optimization target

Copy link

Choose a reason for hiding this comment

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

We are considering consolidating all new functionality into the SuperchainConfig, though having a specific contract doesn't sound like a bad option either.

This contract would manage the dependency set and the ability to add a chain to it.

Also we should consider that this contract will have to be set as the dependency manager of the SystemConfig.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would be in favor of either the SuperchainConfig or adding another contract, with slight preference for the SuperchainConfig to reduce the number of contracts that we need to manage/deploy


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
Copy link
Contributor

Choose a reason for hiding this comment

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

Related to some of my questions about (why do we need dependency set info in the system config and the DependencySetManager, and do we really need the DependencySetManager), I'd like to see more alternatives and justification for this specific lockbox design, compared to other lockbox designs.

An example: Have we considered deprecating the portal, and having the lockbox emit deposit events with a chain ID? The obvious downside is now this requires changes to the derivation path, but it does mean we can get rid of an entire contract which is nice

Copy link

Choose a reason for hiding this comment

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

Deprecating the portal in favor of developing a new SharedPortal sounds like a good long-term goal, but it would be far beyond the scope of the ETH Lockbox feature. Creating this new SharedPortal looks like a massive and highly sensitive project that would need debate and coordination across multiple teams to bring it to life. We think this is a valid but complex question that could significantly alter the direction of this task. We're interested to hear what others think about it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer to not add more derivation changes. We have considered a "beacon" style deposit contract, this could be on the roadmap in the future but this feature doesn't make or break the design. I am in favor of the minimal diff that maintains the portal contracts and simply holds its ether in a shared lockbox

Copy link
Contributor

Choose a reason for hiding this comment

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

We do need a dependency set manager that orchestrates the dependency set of the entire cluster, unless we do have a shared system config


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
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to see security considerations fleshed out a bit more. Arguably the risks aren't that much different than storing all this ETH in separate portal proxies that point to the same implementation, but there are risks with both the ETH migration and having a giant honeypot of funds. What is the simplest and most secure migration approach and architecture we can come up with? How do we gain confidence in the implementations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're gonna focus on this part; we will come back with some different approaches that we're currently analyzing


// Function to add a chain to the dependency set
function addChain(uint256 chainId) external onlyOwner {
require(systemConfigInterops[chainId] != address(0), "DependencySetManager: Chain not registered");
Copy link
Contributor

Choose a reason for hiding this comment

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

We will rename SystemConfigInterop to SystemConfig, its a temporary naming scheme. Same with renaming OptimismPortal2 to OptimismPortal, so you can refer to them with those names


A minimal set of functions should include:

- `lockETH`: Accepts ETH from the `depositTransaction` originating from a valid `OptimismPortal2`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Something to think about is decoupling the proof verification logic itself from the OptimismPortal completely, see the discussion in ethereum-optimism/specs#361

This will help to reduce the size of the OptimismPortal contract, it is at max codesize. It also would make it easier to slot in alternative proof systems. Just bringing this up because its related code, this may not be a good idea to include as part of this change as its scope bloat.

Its likely possible that the required modifications to the portal for this feature can be included without going over the codesize, but if its absolutely not possible to stay below max codesize then we will need to do the above issue first.

Copy link

Choose a reason for hiding this comment

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

Once we define the migration approach, we will try to apply the code changes needed and check if it reach the size limit. If we are able to avoid hitting the limit, we will leave it like that and apply the changes to the portal. If we hit the size limit, we will need to revisit and tackle the possible portal decoupling.

@zainbacchus
Copy link

@tynes
Copy link
Contributor

tynes commented Nov 4, 2024

One consideration now that we have a contract for managing the dependency set - should we make the full dependency set legible from within each L2? This would prevent the need to send to chains that do not have the local chain in their dependency set

We could assume this by observing the dependency set locally when sending a message through the L2ToL2CrossDomainMessenger, but this would have implications about the topology about all possible chain clusters. I do not love the idea of enforcing that all possible clusters MUST be a mesh

@tynes
Copy link
Contributor

tynes commented Nov 4, 2024

We need to align on whether or not we want to be supporting non-complete graphs in the dependency set. We can make assumptions that it must be a full mesh. Right now we do not make this assumption

@tynes
Copy link
Contributor

tynes commented Nov 6, 2024

One consideration now that we have a contract for managing the dependency set - should we make the full dependency set legible from within each L2? This would prevent the need to send to chains that do not have the local chain in their dependency set

We could assume this by observing the dependency set locally when sending a message through the L2ToL2CrossDomainMessenger, but this would have implications about the topology about all possible chain clusters. I do not love the idea of enforcing that all possible clusters MUST be a mesh

Lets not worry about this as it adds scope and we can revisit in the future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants