ethereum-optimism / design-docs

MIT License
19 stars 11 forks source link

design-doc: interoperable ether #25

Closed tynes closed 2 months ago

tynes commented 3 months ago

Description

Adds a design doc for what interoperable ether. This is a core feature for interop devnet v2.

The ISuperchainERC20 spec can be found here

tynes commented 3 months ago

This should include the following options:

It should also cover how custom gas token impacts things

tynes commented 3 months ago

One major problem is the liquidity of weth on a certain chain, a lack of weth would mean outbound liquidity constraints. It could be solved with a relaying system that charges fees and pays out to LPs, if the fees grew when liquidity was lower then it would create the incentive to rebalance

smartcontracts commented 2 months ago

I'm going to be taking over this spec/design work from @tynes. Dropping my own version of the initial design doc here as a comment before I likely turn this into its own PR following the design review meeting today.

Context and Key Problems

ETH is the native asset of Ethereum and has by extension also become the native asset of many Ethereum L2 blockchains. In its role as a native asset, ETH can be used to pay for transaction fees and can be transferred from account to account via calls with attached value. ETH plays a significant role in the economics of most L2s and any protocol that enables interoperability between chains must be able to account for ETH.

We want to handle native assets other than ETH

Not all chains using the OP Stack use ETH as the native asset. We would like these chains to be able to interoperate with chains that do use ETH as a native asset. Certain solutions that might work when all chains use ETH as a native asset begin to break down when alternative native assets are introduced. For example, a protocol that burns the native asset on one chain and mints it on another will work if both chains use the same native asset but will obviously fail if either chain uses a different native asset.

We want to minimize protocol complexity

Support for native ETH opens the door to unnecessary complexity. Any solution to this problem should aim to minimize the amount of protocol code required to support native ETH. This generally points towards an app-layer solution if possible but does not preclude a protocol-layer solution as long as we minimize implementation size.

We want to maximize functionality

Any solution should strive to maximize the functionality of the underlying message-passing protocol. Support for native ETH should not unnecessarily restrict the interop protocol.

We want to streamline the user experience

An ideal solution would make it possible to streamline the user experience such that ETH transfers between chains look just like ETH transfers between addresses on the same chain. Much of the user experience can be solved at the wallet level but it’s also important that the underlying protocol doesn’t require an unnecessary number of transactions to

Proposed Solution

We propose solving for interoperable ETH by introducing a predeployed WETH contract that supports the ISuperchainERC20 interface. This contract, referred to as “Superchain WETH” for the remainder of this document, would be redeemable for the native asset on chains that use ETH as a native asset but would only be usable in its wrapped ERC-20 form on chains that use any other native asset.

Considerations

Dealing with existing the WETH predeploy

We have an existing WETH predeploy that is already used by a number of contracts on OP Mainnet and other OP Stack chains. Adding a new WETH predeploy would potentially fragment ETH liquidity in certain app-level protocols. We should carefully explore the impact of this fragmentation and determine if this impact justifies a fork that upgrades the existing WETH contract rather than introducing a new predeploy.

It is important to note that the existing WETH contract represents “wrapped native asset” and not “wrapped ETH” and any solution must account for this discrepancy. We want Superchain WETH to universally represent “wrapped ETH” on every chain. An ideal solution here would not create a massive diff between ETH and non-ETH chains.

Supplying ETH liquidity

Superchain WETH introduces the need to supply some sort of ETH liquidity that makes it possible to actually withdraw WETH into ETH. We can easily credit a WETH balance on a receiving chain but the receiving WETH contract will not actually have the ETH balance to facilitate the transfer into native ETH. We propose solving this issue by giving the Superchain WETH contract access to a very large (uint248 max) balance of ETH on each chain. Other projects (notably Scroll) have taken a similar strategy to handling ETH bridging as an alternative to minting ETH natively.

Allowing WETH to access a large ETH balance should not introduce any security concerns. WETH balances that allow ETH withdrawals would still be governed by the standard WETH logic. We must make sure to maintain the key invariant that the total amount of withdrawable WETH is exactly equal to the amount of deposited WETH.

We can implement this logic by either (1) crediting the WETH contract directly with a large ETH balance or (2) crediting some other contract (the ”Superchain Liqudiity” contract) with a large ETH balance and exclusively allowing WETH to tap into this contract. Crediting WETH directly is a simpler design but has the unintended side-effect of also creating an artificially large total WETH supply on paper because the standard WETH9 contract reads the total supply from address(this).balance. We need to consider whether we should modify WETH9 to compute the total supply from deposits and withdrawals or if we should introduce a separate Superchain Liquidity contract to sidestep this total supply issue.

Handling chains that use native assets other than ETH

As previously noted, we want Superchain WETH to represent “wrapped ETH” on all chains regardless of the native asset. This means that Superchain WETH must be able to distinguish between chains that use ETH as a native asset and chains that do not. Superchain WETH on ETH-native chains should be redeemable for the native asset while Superchain WETH on all other chains must remain in the ERC-20 form.

Streamlining user experience

An ideal user experience would mean that sending ETH from one chain to another feels just like sending ETH between two accounts on the same chain. We can mostly solve this at the wallet level but we should aim to keep the transfer process to a single transaction.

We can get pretty far by providing two ways to interact with Superchain WETH:

  1. Call a function sendETH that wraps the msg.value, transfers the WETH balance to the Superchain WETH contract on the receiving chain, and unwraps ETH to the recipient address if the receiving chain uses ETH as a native asset. ETH would remain in WETH form if the receiving chain uses a different native asset.
  2. Call a function sendERC20 that wraps the msg.value, transfers the WETH balance to the Superchain WETH contract on the receiving chain, and keeps the balance in WETH regardless of the native asset used by the receiving chain.

As usual, we could reduce this into a single function with toggles if desired:

function sendWETHTo(
    address recipient,
    uint256 amount,
    uint256 chainId,
    bool unwrap
)
    public
    payable
{
    // If amount is zero, send using WETH balance.
    // If amount is nonzero, send using msg.value.
    // Send message to recipient chain.
}

function relayWETHTo(
    address recipient,
    uint256 amount,
    bool unwrap
)
    public
{
    // Check that this is from the cross domain messenger.
    // Increase the recipient's balance.
    // If unwrap and this is a native ETH chain then perform unwrap.
}
tynes commented 2 months ago

The weth supply is not accurate because you can use selfdestruct to transfer ether to the contract without any execution (where it would usually mint weth). This would increase the totalSupply of weth without minting any erc20 tokens.

I still lean towards keeping the liquidity in its own contract to keep a clear boundary around the superchain ending bug of that ether being able to be removed somehow. The control flow of accessing this locked ether should be defined super clearly and it unlocks future modifications to the superchain weth predeploy in the future

tynes commented 2 months ago

This should be a proxied contract and only upgradable by the system transactions

tynes commented 2 months ago

Can we make this solution more generic? So it doesn't enshrine ether as deeply in the design

tynes commented 2 months ago

Should we use the mirror approach for this to solve the fragmentation issue?

tynes commented 2 months ago

After chatting with @smartcontracts about our constraints and optimization targets, we decided that we shouldn't focus on making the solution more generic or use the mirror approach. Right now there is extremely low usage of custom gas token chains, so it would be a premature optimization to make it more generic right now. We can solve the usecase for the chains that contribute the most revenue to the collective now (all ether as gas) then think about a more generic solution in the future

skeletor-spaceman commented 2 months ago

After chatting with @smartcontracts about our constraints and optimization targets, we decided that we shouldn't focus on making the solution more generic or use the mirror approach. Right now there is extremely low usage of custom gas token chains, so it would be a premature optimization to make it more generic right now. We can solve the usecase for the chains that contribute the most revenue to the collective now (all ether as gas) then think about a more generic solution in the future

What are the tradeoffs of not using the mirror contract and using a new custom pre-deploy to handle the WETH case ?

Could we get more insight into the reasoning behind the decision?

smartcontracts commented 2 months ago

What are the tradeoffs of not using the mirror contract and using a new custom pre-deploy to handle the WETH case ?

I think the main reason not to use the mirror contract is because the chain contracts end up looking different if you're on a custom gas chain or not. I don't really love the idea of having some chains have a mirror contract while other chains just have this new Superchain WETH contract.

Mirroring would also require upgrading the existing WETH contract which requires a hardfork. Would be very annoying. Current approach works well enough, doesn't need a hardfork, and doesn't end up with different contracts on different chain types.

smartcontracts commented 2 months ago

Approving but would like to see @skeletor-spaceman's response to the above before merging.

skeletor-spaceman commented 2 months ago

Mirroring would also require upgrading the existing WETH contract which requires a hardfork

yeah, this is a big counter-point to the Mirror approach. Since the standard bridge just sends raw msg.value, and WETH is not used as a _isOptimismMintableERC20(...). where the internal mint on WETH, would pull from the "infinite" ETH pre-mine

with this in mind, and going back to one of the key-points above:

We should carefully explore the impact of this fragmentation and determine if this impact justifies a fork that upgrades the existing WETH contract rather than introducing a new predeploy.

I'm still a bit hesitant on why we would need to create a new "custom" pre-deploy that would behave almost exactly as any other superc20, for which we could leverage all the superc20 tooling and periphery for a better more comprehensive UX/DX. I'd love to avoid "contract/flow" fragmentation when sending tokens, native or not.

mirror is out of the question, we agree there. liquidity fragmentation is inevitable without a complex hard-fork that would modify the WETH pre-deploy for it to be able to handle ETH + custom gas tokens under the same address. (even if possible, is a mess)

but, why do we need superWETH to be a pre-deploy?

smartcontracts commented 2 months ago

Got it, if the question is predeploy vs not, I have no strong opinions there. cc @tynes for input.

tynes commented 2 months ago

but, why do we need superWETH to be a pre-deploy?

The superchain erc20 spec includes the fact that the address is the same on all chains so making superchain weth be the same address on all chains as a predeploy is the most simple option. Since we want this on all op stack chains, the two options are predeploy or preinstall, I definitely lean towards predeploy since the existing weth aka wrapped native asset is a predeploy

for which we could leverage all the superc20 tooling and periphery for a better more comprehensive UX/DX.

The ABI on superchain weth will implement super erc20, so the tooling will still work. super erc20 is an interface, not all super erc20 tokens must be mirrors, superchain weth is an instance of a super erc20 that is meant to be weth on all chains, custom gas token or not

tynes commented 2 months ago

We need to be careful of pulling in too many features, ie making superchain weth support IOptimismMintableERC20 and allowing L1 weth to populate it. That seems like a nice to have feature in the future, we don't necessarily need that now

skeletor-spaceman commented 2 months ago

@tynes agreed, my understanding was that if possible we'd want to keep the number of pre-deploys at a minimum. But if it's easier to just make this a pre-deploy, I'm onboard.