SIP-280: PerpsV2 (Perps Upgradability)

Author
StatusDraft
TypeGovernance
NetworkEthereum & Optimism
ImplementorLeonardo Massazza (@leomassazza)
ReleaseTBD
Created2022-09-26

Simple Summary

Add upgradability capabilities to current Futures implementation as a first step to add new features to it. Note, in this SIP Futures and Perps terms are interchangeale.

Abstract

In order to provide upgradability capabilities to Futures it needs to replace current FuturesMarket implementation. Based on how current Synths work, this SIP will replace the single FuturesMarket contract with a set of contracts:

  • a proxy in front of it to have a fixed address.
  • an state contract to hold all the FutureMarket state that can be later migrated if needed.
  • a set of contracts (due to cotnract size limitations) with the implementation only that uses the state and are pointed by the proxy.

This will require some addaptation based on the current State and Proxy to allow the implementation to be split in parts.

Motivation

The current Futures contracts are immutable and in order to add new features to it or if a bug is discovered, we need to provide upgradability. This is the first SIP of a series where new features are added and this effort is required to achieve that goal. The intention to maintain it separated from the new features introduced is to allow for minimum changes for the code review and audit.

Specification

Overview

This change will be done by duplication current Futures contracts, scripts and tests as PerpsV2 (replacing the names and references), then the FuturesMarket.sol contract will be split into ProxyPerpsV2Market.sol as the market proxy, PerpsV2MarketState.sol as the state, and PerpsV2Market.sol, PerpsV2MarketViews.sol, PerpsV2MarketNextPriceOrders.sol as the implementation isolated on the different aspects of the functionality.

In order to maintain homogeinity in the behaviour and naming, also FuturesMarketManager.sol is duplicated as PerpsV2MarketManager.sol changing the reference of the implementation to the proxy address, and PerpsV2MarketSettings.sol and PerpsV2MarketData.sol to use the appropriate references.

The deployment scripts are added to work with this new complexity and the tests are adjusted to use the new contracts.

Current Futures contract, tests, and scripts are untouched and the new markets will replace the current ones after they are migrated.

Rationale

This rationale behind this process is to get a new set of contracts for PerpsV2 maintaining the current funtionality so that the tests, code review and audit of the code is minimized to reduce the risk of introducing bugs.

This SIP introduces the minimum changes to make the current version upgradable and to release new futures features, and fix bugs if found as soon as possible. In order to get it done (and released) in a short period we propose this intermediate architecture. There is a plan to migrate all perps to the new V3 architecture (V3 is under development at the moment of this writting) that will be more optimized, but it is not certain when Perps V3 (based on V3 archtecture) can be prioritized after V3 is live and other parts of Synthetix system is ported to the new architecture before PerpsV3.

The current Futures's architecture is based on the following components, each one with a different upgradability or migration complexity:

  • FuturesMarketManager.sol: Maintains a list of markets in state. Not upgradable, but migrable via script to a new instance. Small ammount of data.

  • FuturesMarketSettings.sol: Upgradable. No state maintaned in the contract.

  • FuturesMarketData.sol: Upgradable. No state maintaned in the contract.

  • FuturesMarket.sol: One per each market. Maintains all the markets positions for the market. Not upgradable and difficult to migrate since there's no way to retrieve the data onchain.

    • MixinFuturesViews.sol: Mixin that is used in FuturesMarket. All the views are contained here.
    • MixinFuturesNextPriceOrders.sol: Mixin that is used in FuturesMarket. Maintains the next price orders state and implements the next price flow logic.

The proposed changes to the architecture, and their new maintenance, upgradability and migration complexity is shown below:

  • PerpsV2MarketManager.sol: Maintains a list of markets in state. Not upgradable, but migrable via script to a new instance. Small ammount of data.

  • PerpsV2MarketSettings.sol: Upgradable. No state maintaned in the contract.

  • PerpsV2MarketData.sol: Upgradable. No state maintaned in the contract.

  • ProxyPerpsV2.sol: One per each market, is the entry point of each market. Not upgradable, but migrable via script to a new instance, it just maintains the market implementation(s) addresses.

    • PerpsV2MarketState.sol: Maintains all the markets positions and next price orders for the market. Not upgradable but easy to migrate since provides access to all the market positions data to the authorized associate contracts.
    • PerpsV2Market.sol: Implements all the basic futures flows and doesn't store any state information. Easily upgradable.
    • PerpsV2MarketViews.sol: Implements all the views for the market. It doesn't store any state information. Easily upgradable. Direct replacement of MixinFururesViews
    • PerpsV2MarketNextPriceOrders.sol: Implements the next price orders flows for the market. It doesn't store any state information. Easily upgradable. Direct replacement of MixinFururesNextPriceOrders

Technical Specification

This architecture refactor is basically a change on the state variables location, addition of a proxy interface and split of FuturesMarket contract into small pieces. The interface of Futures is minimal but requuires some new base contract based on current implementations to extend State.sol and Proxy.sol as StateShares.sol and ProxyPerpsV2.sol to enable multiple proxied contracts instead of just one. The changes are detailed below.

ProxyPerpsV2.sol

Based on Proxy.sol and with the introduction of some routing concepts of V3.

It adds the capability to route a call to a the configured contract and if not found default to the proxy target. The routes indicates the function selector that needs to be routed, the target implementation and a flag to identify if it's a view or a transaction call to identify if it needs to set the messageSender on the target (view functions will revert if setMessageSender is called since it changes the state).

Since the proxy has the _emit function that can be called by the implementation(s), it needs to be modified to accept more than one contract (the modifier changed from accept onlyTarget to onlyTargets).

To manage the routes, ProxyPerpsV2 adds the following functions to the interface and events.

/* ========== FUNCTIONS ========== */

function addRoute(bytes4 selector, address implementation, bool isView) external onlyOwner {}
function removeRoute(bytes4 selector) external onlyOwner {}
function getRoutesLength() external view returns (uint) {}
function getRoutesPage(uint index, uint pageSize) external view returns (Route[] memory) {}
function getAllTargets() external view returns (address[] memory) {}

/* ========== EVENTS ========== */

event RouteUpdated(bytes4 route, address implementation, bool isView);
event RouteRemoved(bytes4 route);
event TargetedRouteAdded(address targetedRoute);
event TargetedRouteRemoved(address targetedRoute);

StateShares.sol

Based on State.sol adds the capability to update the state to more than one contract. The references to associatedContract changes to associatedContracts (plural) and the constructor takes now an address array instead of an address.

The introduced modifier changes from onlyAssociatedContract to onlyAssociatedContracts.

To manage the associated contracts, StateShares removes the setAssociatedContract() function and AssociatedContractSet event and are replaced by the following functions and events.

/* ========== FUNCTIONS ========== */

function addAssociatedContracts(address[] calldata associatedContracts) external onlyOwner {}
function removeAssociatedContracts(address[] calldata associatedContracts) external onlyOwner {}
function associatedContracts() external view returns (address[] memory) {}

/* ========== EVENTS ========== */

event AssociatedContractAdded(address associatedContract);
event AssociatedContractRemoved(address associatedContract);

Test Cases

Apart from the duplicatation of all Futures test as PerpsV2 tests and they adaptation to the new architecture (deployment of related contracts), it adds tests for ProxyPerpsV2 and StateShares as well as adding tests to cover security accesibility for the contracts behind the new proxy (that needs to be reachable by the proxy for normal operation and by the owner to the administering functions).

Configurable Values (Via SCCP)

No new values are configurable via SCCP under this implementation.

Copyright and related rights waived via CC0.