Giter VIP home page Giter VIP logo

synthetix-v3's Introduction

Synthetix v3

codecov

Package Coverage
@synthetixio/core-utils codecov
@synthetixio/core-contracts codecov
@synthetixio/core-modules codecov
@synthetixio/main codecov

Documentation

Please refer to the Official Documentation for high level concepts of the Synthetix v3 protocol, as well as auto generated docs from natspec.

Package structure

This is a monorepo with the following folder structure and packages:

.
├── markets                      // Standalone projects that extend the core Synthetix protocol with markets.
│   ├── legacy-market            // Market that connects Synthetix's v2 and v3 versions.
│   └── perps-market             // Market extension for perps.
│   └── spot-market              // Market extension for spot synths.
│   └── bfp-market               // Market extension for eth l1 perp.
│
├── protocol                     // Core Synthetix protocol projects.
│   ├── governance               // Governance contracts for on chain voting.
│   ├── oracle-manager           // Composable oracle and price provider for the core protocol.
│   └── synthetix                // Core protocol (to be extended by markets).
│
└── utils                        // Utilities, plugins, tooling.
    ├── common-config            // Common npm and hardhat configuration for multiple packages in the monorepo.
    ├── core-contracts           // Standard contract implementations like ERC20, adapted for custom router storage.
    ├── core-modules             // Modules intended to be reused between multiple router based projects.
    ├── core-utils               // Simple Javascript/Typescript utilities that are used in other packages (e.g. test utils, etc).
    ├── deps                     // Dependency handling (e.g. mismatched, circular etc.)
    ├── docgen                   // Auto-generate docs from natspec etc.
    ├── hardhat-storage          // Hardhat plugin used to detect storage collisions between proxy implementations.
    └── sample-project           // Sample project based on router proxy and cannon.

Router Proxy

All projects in this monorepo that involve contracts use a proxy architecture developed by Synthetix referred to as the "Router Proxy". It is basically a way to merge several contracts, which we call "modules", into a single implementation contract which is the router itself. This router is used as the implementation of the main proxy of the system.

See the Router README for more details.

⚠️ When using the Router as an implementation of a UUPS Universal Upgradeable Proxy Standard be aware that any of the public functions defined in the Proxy could clash and override any of the Router modules functions. A malicious proxy owner could use this type of obfuscation to have users run code which they do not want to run. You can imagine scenarios where the function names do not look similar but share a function selector. ⚠️

Information for Developers

If you intend to develop in this repository, please read the following items.

Installation Requirements

  • Foundry
  • NPM version 8
  • Node version 16

Console logs in contracts

In the contracts, use import "hardhat/console.sol";, then run DEBUG=cannon:cli:rpc yarn test.

Deployment Guide

Deployment of the protocol is managed in the synthetix-deployments repository.

To prepare for system upgrades, this repository is used to release new versions of the protocol and markets.

Preparing a Release

Setup Cannon

  • Run yarn upgrade-interactive and make sure that @usecannon/cli and hardhat-cannon and updated to the latest versions.
  • After installing for the first time, run yarn cannon:setup to configure a reliable IPFS URL for publishing packages and any other preferred settings.

Setup npm

  • Unless npm whoami returns an npm account with publishing permissions for the @synthetixio organization, confirm an @synthetixio npm publishing key is set as $NPM_TOKEN in the .env file or prepend NPM_TOKEN=_ to the command used for publishing below.

Publish Dev Release

  • Confirm you are on the development branch you’d like to release and that there are no git changes git diff --exit-code .
  • Publish the release with yarn publish:dev for the pre-release (no git tag, version looks like 1.2.3-<GIT_SHA>.0)
  • If you aren't using an EIP-1193 compatible wallet, prepend CANNON_PRIVATE_KEY=<PRIVATE_KEY> to the following command.
  • In the directory for each package you’d like to publish to cannon, run yarn deploy
  • After successful publish, there should be no diff in git. But if there is a diff - make sure you reset any changes, fix publishing issues and re-publish again. Double-check all the package.json files, revert dependencies' version changes back to "workspaces:*".

Publish Official Release

Each step is necessary, do not skip any steps.

  • Verify what has changed since the last release

    yarn changed
  • Confirm you are on the main branch and that there are no git changes git diff --exit-code . and you have write access to main branch

    git fetch --all
    git checkout main
    git pull
    git diff --exit-code .
  • Publish the release with yarn publish:release. (After successful publish, there should be no diff in git.)

  • If you aren't using an EIP-1193 compatible wallet, prepend CANNON_PRIVATE_KEY=<PRIVATE_KEY> to the following command.

  • In the directory for each package you’d like to publish to cannon, run yarn deploy

synthetix-v3's People

Contributors

0xjocke avatar 0xmithrandir avatar andytcf avatar barrasso avatar davidvuong avatar dbeal-eth avatar fritzschoff avatar i-stam avatar jaredborders avatar jmzwar avatar kaleb-keny avatar leomassazza avatar mjlescano avatar noahlitvin avatar noisekit avatar rickk137 avatar sunnyvempati avatar synthetixio-team avatar tburm avatar thanpolas avatar theethernaut avatar tommyrharper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

synthetix-v3's Issues

Dynamically generate a Mixin that exposes hardcoded module addresses via internal calls

Multiple experiments were carried out to see if we can have modules interact with each other with a lower gas cost:

The conclusion of these experiments was to try to not only generate the Solidity code of the router, but also generate a mixin that any module can inherit, exposing the addresses of all the modules via constants.

This poses many challenges:

  1. The mixin needs to be generated before the modules are deployed, and since the module addresses are not known before they are deployed, it becomes a chicken vs egg problem. However, we can predict what module addresses will be, since they are deterministically calculated from the address of the deployer EOA (or contract?) and its nonce.

  2. Since a project may target multiple networks/instances, it may have multiple routers such as RouterLocal.sol, RouterKovan.sol, etc. This duplication should also apply to this mixin. The duplication in the router code is ugly but tolerable, but the duplication in the mixin would be too weird. I.e.

contract AModule is RegistryMixinLocal { ... }
or
contract AModule is RegistryMixinKovan { ... }

A solution to this issue could be to have a single mixin:
contract AModule is RegistryMixin
and allow it to change depending on the last deployment. This means that this Solidity file will be constantly changing, depending on what the last targeted network was. Which is weird too, but tolerable.

In fact, if this works, the same principle could be applied to the router, effectively removing the need to keep multiple routers around in the codebase. Since the deployer always has all the necessary data to generate a new router, then why keep duplicates around, or even keep any around in the source code?


Generation process

Basic (excessive gas usage on deployment)

  • Generate a fake AddressMixin with random addresses
  • Compile all modules to find out the ones that changed due to explicit code change and by using the mixin
  • Identify all contracts to deploy (and the order that will be used)
  • Calculate and collect all modules new addresses
  • Fill the missing modules addresses (the ones that weren’t re-deployed) using latest deployment info on the instance
  • Generate a new AddressMixin with the right addresses
  • Deploy all system (it will always deploy ALL MODULES that depends on AddressMixin)
  • Validate that the AddressMixin has the right addresses

This process will always try to generate a new AddressMixin even if no modules were updated on the first time

Improved Process (only deploy when a module was updated)

  • First identify if any module was updated
  • If any module was updated, continue with the Basic process. If not, the current AddressMixin is still valid

it will deploy ALL MODULES that depends on AddressMixin when any module was updated

Improved Process 2 (tag Addressable modules)

This improvement also adds a tag to the modules that are addressable (the ones that are potentially usable from another module, and hence has the address exported in AddressMixin)
i.e. // address-mixin isAddressable

  • Set a tag on the Modules source (this is done only once while coding and the tag can be added later if there's a need to use a module that wasn't set originally as addressable)
  • Identify Modules that are addressable and check if any was updated
  • If any addressable module was updated, continue with the Basic process. If not, the current AddressMixin is still valid

it will deploy ALL MODULES that depends on AddressMixin when any addressable module was updated

Bug: new deployment overrides completed deployment

npx hardhat deploy --network local --clear --no-confirm
All good. Generates 2021-09-06-00.json.

npx hardhat deploy --network local --no-confirm
Does not generate a new file, which is good, since no changes means that a new deployment file didn't need to be generated.
However, it generates the router. This task could be skipped since there is no need to generate a router if no modules changed. So, no green output in the console. Perhaps even gray output specifying the no-op could help.
Similarly, it prints "Deployment marked as completed" in green. This is also a no-op.

The idea would be to only see colors when things happen during a deployment.

Clean up list

  • Stop using hre.deployer.paths
  • Do not use config in any tools - tools should only use primitives that are very intuitive
  • Do not copy config.paths into config.deployer.paths
  • Do not use config.deployer for anything dynamic, since this is supposed to be just config
  • Forbid usage of .previousData in hre.deployer?
  • Forbid usage of .file in hre.deployer?
  • Is config.deployer.proxyName used?
  • Document argument-types.js util
  • Split out some functions in contracts util to core-js
  • Move logger to core-js
  • Move git and package to core-js
  • Move prompter to core-js
  • Move relative-path to core-js
  • Move string to core-js
  • Split deployer utils to internal/external utils: Internal are those that need the hre env, and external are the ones that dont - E.g. transactions.js

Bug: router not updated after fixing a selector collision

Steps to reproduce:

  • have a basic system working
  • deploy it: npx hardhat deploy --network local --clear
  • create a new module/contract with a function similar to other contract (same name and parameters)
  • deploy it: npx hardhat deploy --network local --clear
    • you're going to see an error found by the tooling indicating there's a selector collision
  • rename the function on the new contract created
  • try to deploy it again: npx hardhat deploy --network local --clear
    • the error is not detected by the tooling (in fact the router is not updated) but by the solidity compiler. In order to continue working the dev should delete manually the router.

Research OZ Governor in depth

Contracts

  • ERC20Permit - EIP 2612 implementation, allowing tokens to approve and transfer in a single tx (with a signature) - Not really a governance thing, but super cool still.
  • ERC20Votes - Token extension which keeps track of historical user balances. These balances can be used to vote at a particular block, and can even be delegated to other users.
  • AccessControl - Role based access control
  • TimelockController - Extension of AccessControl, that introduces a timer before any role protected actions
  • Governor - Abstract and central contract for governance. It accepts, stores and executes proposals, but does not define how votes are counted, or when a proposal has consensus.
  • GovernorVotes - Determines the weight that an account has when casting a vote by looking at the last snapshot for the account
  • GovernorCountingSimple - For each proposal, keeps track of for and against votes. It determines when a proposal succeeds (when for > against), and when quorum has been reached (for + abstain >= quorum).
  • GovernorVotesQuorumFraction - Calculates quorum as 4% of totalSupply when voting starts on a proposal.
  • GovernorTimelock - Without this, a Governor can execute proposals as soon as they succeed. With this, a proposal that succeeds can only be queued for execution after the timelock period.

Experiments

Stop using hre.deployer.paths

Even though its practical to calculate paths initially, and use the results in all subtasks, it goes against the principle of making subtasks as self-sufficient as possible.

Detect selector duplicates before making any deployments

Atm, deployment aborts if it finds duplicate selectors. The problem is that this happens when the router is generated, that is after modules have been deployed.

Deploying modules can be avoided, if the check of duplicate selectors is done before.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.