SIP-307: Router Proxy Architecture (V3)

Author
StatusDraft
TypeGovernance
NetworkOptimism
ImplementorAlejandro Santander (@Ethernaut), Leonardo Massazza (@leomassazza), Matias Lescano (@mjlescano)
ReleaseTBD
Created2022-05-31

Simple Summary

This SIP proposes the base architecture for the Synthetix v3 system, as well as all v3 related systems, such as governance instances (spartan-council, etc). This new architecture minimizes complexity during releases, provides a novel way of overcoming the EVM's smart contract size limits, and makes system upgrades very explicit to the community.

Abstract

The architecture will be implemented via low level tooling, implemented as a series of hardhat plugins. These plugins will be generic, allowing any project to use the base architecture. The plugins will allow seamless deployment and validation of system upgrades, as well as command line interaction with deployed instances.

Motivation

The existing v2 architecture has become outdated, and has accumulated too much technical debt. It makes it hard for developers to add new features to the protocol, and is prone to make mistakes. It also makes the release process complicated, and fragile. The new architecture was designed specifically to target these problems, and produce a foundation that easy to build upon, and easy to use during releases.

Specification

Overview

The proposed architecture is basically composed of a fundamental "deployer" plugin. This plugin will identify a system's modules and automatically determine when a module's source code has changed and needs to be re-deployed. Instead of connecting the system's modules via an AddressResolver, modules are "merged" into a single super-contract that uses a technical workaround to overcome the EVM's contract size limitations. This means that no connections have to be made for modules to be able to interact with each other, which is one of the most fragile areas of the v2 architecture.

The merging of the modules is done via a contract generated by tooling, known as the Router, which acts as the implementation of a single proxy for the entire system. The generated router, is simply a table that maps incoming selector calls to their corresponding module. This is an example of such Router code: https://optimistic.etherscan.io/address/0x6209043FcEf509ba5624054Da26Eb8d52a12efcc#code. As you can see, the router will be a very explicit manifestation of the current composition of the system.

Rationale

The proposed architecture's ability to overcome smart contract size limits in a way that minimizes developer efforts provides an ideal way to engineer complex systems like Synthetix, which are very iterative and require frequent updates. This is what the v3 architecture optimizes for. The router proxy architecture is also efficient, since it uses modern delegatecall (as opposed to v2's call) based proxies, and constructs its routing table using Yul assembly language, resulting in a proxy system that is more efficient than other proxies such as OpenZeppelin's transparent proxies.

The delegatecall method is chosen for proxies, since it makes coding much easier. However, misuse of this type of proxies can cause storage collisions. However, the proposed architecture includes extensive abstract syntax tree validations to ensure that storage collisions do not exist. What this means is that we remove complexity from the developer, and transfer it to the tooling.

Since the tooling is generic, and it can be used by other projects, we expect it to become more robust as it gains popularity in web3.

Technical Specification

The proposed architecture is being developed here: https://github.com/Synthetixio/synthetix-v3/tree/main/packages

Next, we describe other characteristics of the architecture.

Universal Upgradeable Proxy Standard

The main system proxy is an UUPS proxy which is more gas efficient than transparent proxies by implementing the upgradeability functions in the implementation instead of the proxy. In this architecture, we develop a way of ensuring that all upgrades are further upgradeable via a special mechanism in the UpgradeModule.

Satellites

Since the deployer is 100% generic, any contract that needs to be deployed and is not a module is considered a "satellite". An example of such a contract will be the v3 SNX token. This will be a "dumb" ERC20 token, fully compliant to the ERC20 standard, that is managed by one of the system's modules and is not the system itself. All satellites will also be upgradeable through the system modules that manage them, and will also use the UUPS architecture.

Apart from the benefit of using satellites for compliance with standards, and the separation of systems from tokens, satellites also solve an issue imposed by the router architecture. This issue arises from the fact that the router requires that all system functions must be unique. I.e. a system cannot have two transfer functions, one in the SNX token and another in a synth. Since these tokens will not be part of the system itself, i.e. not modules, being satellites removes this restriction imposed by the router.

Execution context

Since the new architecture uses delegate call proxies, the execution context of the system will be the proxy itself. This means that all system state will be in a single contract, and modules will simply specify the system's code. This simplifies development significantly, and will allow for much faster and safer iteration of the protocol. All state is accessible to all modules immediately, without the need to perform calls between system components. No special treatment has to be given to the message sender of a transaction, nor the emission of events.

To avoid conflicts within this globally state contained in the main proxy, the system will use namespaces for each module. E.g. io.syntheitx.election, io.synthetix.rates, etc. Such namespaces will be used both by developers for clarity, as by tooling for systematically checking for storage collisions. Namespaces can only be appended to, and cannot be reordered.

Generic tooling

All hardhat plugins and dependency libraries are developed in a way that is completely agnostic to the Synthetix protocol. This allows the code to be simple and robust, and invites other protocols to use the architecture. Our hope is that, as other protocols use it, the simple code becomes more robust and reliable with time, only making all protocols that rely on it stronger. Since the deployer does not contain any Synthetix specific Javascript code, all edge case implementations need to be coded in a migration contract, which will allow the community to very explicitly review a system upgrade or change.

Routing

In a way, this architecture is similar to the Diamond Proxy pattern, but instead of relying on storage to define the system's composition at any time, it clearly maps it out in a hard coded table within a verified contract. Again, this allows anyone to very easily verify and understand the composition of the system at any given time. The routing table also uses a binary search algorithm that makes the routing of calls to their corresponding modules highly gas efficient.

Solidity version

The architecture is built on Solidity's latest 0.8.x versions.

Safety checks

The tooling performs a series of checks on systems based on this architecture, such as ensuring that storage collisions do not exist, modules are frozen when not initialized, upgrades cannot be bricked, etc.

Beacon proxies

Beacon proxies will allow modules that manage multiple ERC20 (E.g. synths) to upgrade all synths with a single transaction. In this sense, synths would also be satellites, each having their own functions like mint, transfer, etc. The "beacon" is simply a contract that stores the current implementation code for all the synths. The module in charge of managing synths simply has to notify the beacon of an upgrade, and this upgrade will be propagated atomically to all satellite synths.

Package layout

  • deployer - hardhat plugin in charge of managing updates to systems based in this architecture
  • cli - hardhat plugin that allows interaction with any deployed system and its sattelites on any chain via the command line interface
  • core-js - generic Javascript utilities used by other packages
  • core-contracts - generic contracts such as ERC20, ERC721, etc (replacement of OpenZeppelin)
  • core-modules - module implementations common to multiple systems, such as OwnerModule, UpgradeModule, ElectionModule, etc
  • synthetix-governance - Synthetix specific governance module implementations
  • spartan-council - project based on this architecture that uses the ElectionModule
  • etc

Copyright and related rights waived via CC0.