SIP-116: Optimism bridge update

Author
StatusImplemented
TypeGovernance
NetworkOptimism
ImplementorTBD
ReleaseTBD
Created2021-02-25

Simple Summary

We propose to make use of the upcoming and last Optimism regenesis, to upgrade the bridge contracts in a way that has no withdrawal downtime. The upgrade would allow future bridge upgrades to also not have any withdrawal downtime, and would make the bridge conform to the new standard bridge interface being adopted by the community.

Abstract

The Ethereum and Optimism bridge contracts, SynthetixBridgeToOptimism and SynthetixBridgeToBase, would be replaced with new versions that conform to the new bridge standard. This involves renaming some functions, but keeping the existing functionality mostly intact. The SNX currently deposited in SynthetixBridgeToOptimism would be transferred to a new SynthetixBridgeEscrow contract, solely in charge of holding SNX for deposits. This would allow future bridge upgrades to occur without moving any funds, since any bridges in the future would all share the same deposit pool. Additionally, the new contracts would allow to suspend the initiation of deposits or withdrawals, while continuing to allow finalization, which is a feature that currently does not exist in the bridges and necessary for bridge upgrades.

Motivation

The Spartan Council has previously considered upgrading the bridges, but the idea was shelved due to the complication of inter-chain asynchronicity. The problem is that withdrawals that had already been initiated but not yet finalized before the bridge migration, would eventually finalize against the old SynthetixBridgeToOptimism contract, which would no longer hold the corresponding SNX deposit, and thus fail. As a consequence, the upgrade appeared to be forced to involve suspending withdrawals for a week, and then doing the migration. Alternatives that involved no withdrawal downtime were discussed, but they were all very delicate given the capabilities of the existing bridge contract code. With the upcoming Optimism regenesis, there is an opportunity to perform the upgrade without any withdrawal downtime whatsoever, since Optimism will finalize all ongoing withdrawals just before the upgrade.

Even though the existing bridges don't contain any critical issues that require an immediate upgrade, the proposed upgrade would make future upgrades easier, which should come in handy if there ever any urgency to upgrade.

Specification

Overview

A few changes would need to be made to the bridge contracts, SynthetixBridgeToOptimism and SynthetixBridgeToBase, and a new contract SynthetixBridgeEscrow would need to be created.

The new bridge contracts should be deployed, and the deposit SNX migrated to the new deposit contract.

Rationale

To conform to the new standard bridge interface, the bridge contracts, SynthetixBridgeToOptimism and SynthetixBridgeToBase, will have a few functions renamed, and some new functions added. The new functions don't introduce any major functionality, but merely extend the existing functionality with added flexibility.

A new deposit/withdrawal initiation mechanism will be added to the SynthetixBridgeToOptimism and SynthetixBridgeToBase. This mechanism will allow a bridge to stop accepting deposit or withdrawal initiation, while still allowing finalization. The idea is that future bridge updates will involve deploying new bridges, while partially disabling the old bridges to allow them to finalize their deposits and withdrawals. Once this happens, they can be disconnected from the SynthetixBridgeEscrow contract, and thus completely disabled.

The SynthetixBrideToOptimism contract will be modified so that it no longer holds any SNX, and will instead forward the deposit to the new contract SynthetixBridgeEscrow. When finalizing a deposit, SynthetixBridgeToOptimism will have allowance to pull funds from SynthetixBridgeEscrow.

In terms of the next bridge upgrade, the idea would be that after the new contracts are deployed, the system is suspended, and Optimism finalizes all withdrawals, the old SynthetixBridgeToOptimism's migrate function will be called, effectively disabling it, and transferring all funds to SynthetixBridgeEscrow.

Technical Specification - Standard Bridge Interface

SynthetixBridgeToOptimism should adopt iOVM_L1ERC20Gateway:

interface iOVM_L1ERC20Gateway {
    function deposit(uint _amount) external;

    function depositTo(address _to, uint _amount) external;

    function finalizeWithdrawal(address _to, uint _amount) external;

    event DepositInitiated(address indexed _from, address _to, uint256 _amount);

    event WithdrawalFinalized(address indexed _to, uint256 _amount);
}

SynthetixBridgeToBase should adopt iOVM_L2DepositedERC20:

interface iOVM_L2DepositedERC20 is IUniswapV2ERC20 {
    function withdraw(uint _amount) external;

    function withdrawTo(address _to, uint _amount) external;

    function finalizeDeposit(address _to, uint _amount) external;

    event WithdrawalInitiated(address indexed _from, address _to, uint256 _amount);

    event DepositFinalized(address indexed _to, uint256 _amount);
}

The bridges should implement these interfaces, as well as the previously existing ISynthetixBridgeToOptimism and ISynthetixBridgeToBase interfaces.

The new interface for SynthetixBridgeToOptimism should be:

interface ISynthetixBridgeToOptimism {
    function migrateEscrow(uint256[][] calldata entryIDs) external;

    function depositReward(uint amount) external;

    function depositAndMigrateEscrow(uint256 depositAmount, uint256[][] calldata entryIDs) external;
}

The new interface for SynthetixBridgeToBase should be:

interface ISynthetixBridgeToBase {
    function finalizeEscrowMigration(
        address account,
        uint256 escrowedAmount,
        VestingEntries.VestingEntry[] calldata vestingEntries
    ) external;

    function finalizeRewardDeposit(uint amount) external;
}

Technical Specification - New Suspension Mechanism

The same code should be used for both SynthetixBridgeToOptimism and SynthetixBridgeToBase.

initiationActive = true // set during contracy deployment

modifier requireInitiationActive() {
        depositingActive();
        _;
}

function depositingActive() internal view {
        require(depositsActive, "Initiation deactivated");
}

function suspendInitiation() external onlyOwner {
        initiationActive = false;
        emit InitiationSuspended();
}

function resumeInitiation() external onlyOwner {
    initiationActive = true;
    emit InitiationResumed();
}

Technical Specification - New Bridge Escrow Contract

The bridge would need to access the address of SynthetixBridgeEscrow, which is going to hold all the deposited SNX on the bridge's behalf. We propose to use the address resolver for this.

bytes32 private constant CONTRACT_SYNTHETIXBRIDGEESCROW = "SynthetixBridgeEscrow";

function synthetixBridgeEscrow() internal view returns (address) {
        return requireAndGetAddress(CONTRACT_SYNTHETIXBRIDGEESCROW);
}

When SNX are deposited to the bridge, they should be transferred to SynthetixBridgeEscrow instead of the bridge itsef:

// move the SNX into SynthetixBridgeEscrow
synthetixERC20().transferFrom(msg.sender, synthetixBridgeEscrow(), amount);

Technical Specification - First SNX Migration

  1. First, the new bridges would have to be deployed and connected to the system as part of an official release. This involves both the Ethereum and the Optimism instances to be suspended of course. Ownership of all new contracts is transferred to the Protocol DAO.

  2. At this point, Optimism would continue with the regenesis process, and inform Synthetix when all withdrawals have been finalized.

  3. Synthetix then calls the old SynthetixBridgeToOptimism contract's migrateBridge(address newBridge) function, targeting the SynthetixBridgeEscrow contract. Which transfers all the deposited SNX to the new escrow contract.

  4. The Protocol DAO, as the owner provides infinite allowance to the new SynthetixBridgeToOptimism.

  5. Systems are resumed.

Test Cases

New test cases:

  • depositTo(address to, uint256 amount)

    • Same as deposit(uint256 amount) amount, with
    • msg.sender is account1
    • to is account2
    • amount is deduced from account1's balance in L1
    • amount is minted for account2 on L2
  • withdrawTo(address to, uint256 amount)

    • Same as withdraw(uint256 amount) amount, with
    • msg.sender is account1
    • to is account2
    • amount is deduced from account1's balance in L2
    • amount is released for account2 on L1
  • suspendInitiation()

    • msg.sender is should be the contract owner (otherwise the tx should revert)
    • initiationActive should be set to false
    • an InitiationSuspended event is emitted
  • resumeInitiation()

    • Same as suspendInitiation()
    • msg.sender should be the contract owner (otherwise the tx should revert)
    • initiationActive should be set to false
    • an InitiationResumed event is emitted

Configurable Values (Via SCCP)

No new configurable values are involved with the proposed changes.

Copyright and related rights waived via CC0.