Giter VIP home page Giter VIP logo

synthetix's Introduction

Synthetix

CircleCI codecov npm version Discord Twitter Follow

Synthetix is a crypto-backed synthetic asset platform.

It is a multi-token system, powered by SNX, the Synthetix Network Token. SNX holders can stake SNX to issue Synths, on-chain synthetic assets via the Staking dApp The network currently supports an ever-growing list of synthetic assets. Please see the list of the deployed contracts on MAIN and TESTNETS Synths can be traded using Kwenta

Synthetix uses a proxy system so that upgrades will not be disruptive to the functionality of the contract. This smooths user interaction, since new functionality will become available without any interruption in their experience. It is also transparent to the community at large, since each upgrade is accompanied by events announcing those upgrades. New releases are managed via the Synthetix Improvement Proposal (SIP) system similar to the EIPs

Prices are committed on-chain by a trusted oracle provided by Chainlink.

Please note that this repository is under development.

For the latest system documentation see docs.synthetix.io

DApps

Community

Discord Twitter Follow

For a guide from the community, see synthetix.community


Repo Guide

Branching

A note on the branches used in this repo.

  • master represents the contracts live on mainnet and all testnets.

When a new version of the contracts makes its way through all testnets, it eventually becomes promoted in master, with semver reflecting contract changes in the major or minor portion of the version (depending on backwards compatibility). patch changes are simply for changes to the JavaScript interface.

Testing

CircleCI codecov

Please see docs.synthetix.io/contracts/testing for an overview of the automated testing methodologies.

Module Usage

npm version

This repo may be installed via npm install to support both node.js scripting applications and Solidity contract development.

Examples

💯 Please see our walkthroughs for code examples in both JavaScript and Solidity: docs.synthetix.io/integrations

Solidity API

All interfaces are available via the path synthetix/contracts/interfaces.

⚡ In your code, the key is to use IAddressResolver which can be tied to the immutable proxy: ReadProxyAddressResolver (introduced in SIP-57). You can then fetch Synthetix, FeePool, Depot, et al via IAddressResolver.getAddress(bytes32 name) where name is the bytes32 version of the contract name (case-sensitive). Or you can fetch any synth using IAddressResolver.getSynth(bytes32 synth) where synth is the bytes32 name of the synth (e.g. iETH, sUSD, sDEFI).

E.g.

npm install synthetix

then you can write Solidity as below (using a compiler that links named imports via node_modules):

pragma solidity 0.5.16;

import 'synthetix/contracts/interfaces/IAddressResolver.sol';
import 'synthetix/contracts/interfaces/ISynthetix.sol';

contract MyContract {
  // This should be instantiated with our ReadProxyAddressResolver
  // it's a ReadProxy that won't change, so safe to code it here without a setter
  // see https://docs.synthetix.io/addresses for addresses in mainnet and testnets
  IAddressResolver public synthetixResolver;

  constructor(IAddressResolver _snxResolver) public {
    synthetixResolver = _snxResolver;
  }

  function synthetixIssue() external {
    ISynthetix synthetix = synthetixResolver.getAddress('Synthetix');
    require(synthetix != address(0), 'Synthetix is missing from Synthetix resolver');

    // Issue for msg.sender = address(MyContract)
    synthetix.issueMaxSynths();
  }

  function synthetixIssueOnBehalf(address user) external {
    ISynthetix synthetix = synthetixResolver.getAddress('Synthetix');
    require(synthetix != address(0), 'Synthetix is missing from Synthetix resolver');

    // Note: this will fail if `DelegateApprovals.approveIssueOnBehalf(address(MyContract))` has
    // not yet been invoked by the `user`
    synthetix.issueMaxSynthsOnBehalf(user);
  }
}

Node.js API

  • getAST({ source, match = /^contracts\// }) Returns the Abstract Syntax Tree (AST) for all compiled sources. Optionally add source to restrict to a single contract source, and set match to an empty regex if you'd like all source ASTs including third-party contracts
  • getPathToNetwork({ network, file = '' }) Returns the path to the folder (or file within the folder) for the given network
  • getSource({ network }) Return abi and bytecode for a contract source
  • getSuspensionReasons({ code }) Return mapping of SystemStatus suspension codes to string reasons
  • getStakingRewards({ network }) Return the list of staking reward contracts available.
  • getSynths({ network }) Return the list of synths for a network
  • getTarget({ network }) Return the information about a contract's address and source file. The contract names are those specified in docs.synthetix.io/addresses
  • getTokens({ network }) Return the list of tokens (synths and SNX) used in the system, along with their addresses.
  • getUsers({ network }) Return the list of user accounts within the Synthetix protocol (e.g. owner, fee, etc)
  • getVersions({ network, byContract = false }) Return the list of deployed versions to the network keyed by tagged version. If byContract is true, it keys by contract name.
  • networks Return the list of supported networks
  • toBytes32 Convert any string to a bytes32 value

Via code

const snx = require('synthetix');

snx.getAST();
/*
{ 'contracts/AddressResolver.sol':
   { imports:
      [ 'contracts/Owned.sol',
        'contracts/interfaces/IAddressResolver.sol',
        'contracts/interfaces/ISynthetix.sol' ],
     contracts: { AddressResolver: [Object] },
     interfaces: {},
     libraries: {} },
  'contracts/Owned.sol':
   { imports: [],
     contracts: { Owned: [Object] },
     interfaces: {},
     libraries: {} },
*/

snx.getAST({ source: 'Synthetix.sol' });
/*
{ imports:
   [ 'contracts/ExternStateToken.sol',
     'contracts/MixinResolver.sol',
     'contracts/interfaces/ISynthetix.sol',
     'contracts/TokenState.sol',
     'contracts/interfaces/ISynth.sol',
     'contracts/interfaces/IERC20.sol',
     'contracts/interfaces/ISystemStatus.sol',
     'contracts/interfaces/IExchanger.sol',
     'contracts/interfaces/IIssuer.sol',
     'contracts/interfaces/ISynthetixState.sol',
     'contracts/interfaces/IExchangeRates.sol',
     'contracts/SupplySchedule.sol',
     'contracts/interfaces/IRewardEscrow.sol',
     'contracts/interfaces/IHasBalance.sol',
     'contracts/interfaces/IRewardsDistribution.sol' ],
  contracts:
   { Synthetix:
      { functions: [Array],
        events: [Array],
        variables: [Array],
        modifiers: [Array],
        structs: [],
        inherits: [Array] } },
  interfaces: {},
  libraries: {} }
*/

// Get the path to the network
snx.getPathToNetwork({ network: 'mainnet' });
//'.../Synthetixio/synthetix/publish/deployed/mainnet'

// retrieve an object detailing the contract ABI and bytecode
snx.getSource({ network: 'sepolia', contract: 'Proxy' });
/*
{
  bytecode: '0..0',
  abi: [ ... ]
}
*/

snx.getSuspensionReasons();
/*
{
	1: 'System Upgrade',
	2: 'Market Closure',
	3: 'Circuit breaker',
	99: 'Emergency',
};
*/

// retrieve the array of synths used
snx.getSynths({ network: 'sepolia' }).map(({ name }) => name);
// ['sUSD', 'sEUR', ...]

// retrieve an object detailing the contract deployed to the given network.
snx.getTarget({ network: 'sepolia', contract: 'ProxySynthetix' });
/*
{
	name: 'ProxySynthetix',
  address: '0x322A3346bf24363f451164d96A5b5cd5A7F4c337',
  source: 'Proxy',
  link: 'https://sepolia.etherscan.io/address/0x322A3346bf24363f451164d96A5b5cd5A7F4c337',
  timestamp: '2019-03-06T23:05:43.914Z',
  txn: '',
	network: 'sepolia'
}
*/

// retrieve the list of system user addresses
snx.getUsers({ network: 'mainnet' });
/*
[ { name: 'owner',
    address: '0xEb3107117FEAd7de89Cd14D463D340A2E6917769' },
  { name: 'deployer',
    address: '0xEde8a407913A874Dd7e3d5B731AFcA135D30375E' },
  { name: 'marketClosure',
    address: '0xC105Ea57Eb434Fbe44690d7Dec2702e4a2FBFCf7' },
  { name: 'oracle',
    address: '0xaC1ED4Fabbd5204E02950D68b6FC8c446AC95362' },
  { name: 'fee',
    address: '0xfeEFEEfeefEeFeefEEFEEfEeFeefEEFeeFEEFEeF' },
  { name: 'zero',
    address: '0x0000000000000000000000000000000000000000' } ]
*/

snx.getVersions();
/*
{ 'v2.21.12-107':
   { tag: 'v2.21.12-107',
     fulltag: 'v2.21.12-107',
     release: 'Hadar',
     network: 'sepolia',
     date: '2020-05-08T12:52:06-04:00',
     commit: '19997724bc7eaceb902c523a6742e0bd74fc75cb',
		 contracts: { ReadProxyAddressResolver: [Object] }
		}
}
*/

snx.networks;
// [ 'local', 'sepolia', 'mainnet' ]

snx.toBytes32('sUSD');
// '0x7355534400000000000000000000000000000000000000000000000000000000'

As a CLI tool

Same as above but as a CLI tool that outputs JSON, using names without the get prefixes:

$ npx synthetix ast contracts/Synth.sol
{
  "imports": [
    "contracts/Owned.sol",
    "contracts/ExternStateToken.sol",
    "contracts/MixinResolver.sol",
    "contracts/interfaces/ISynth.sol",
    "contracts/interfaces/IERC20.sol",
    "contracts/interfaces/ISystemStatus.sol",
    "contracts/interfaces/IFeePool.sol",
    "contracts/interfaces/ISynthetix.sol",
    "contracts/interfaces/IExchanger.sol",
    "contracts/interfaces/IIssue"
    # ...
  ]
}

$ npx synthetix bytes32 sUSD
0x7355534400000000000000000000000000000000000000000000000000000000

$ npx synthetix networks
[ 'local', 'sepolia', 'mainnet' ]

$ npx synthetix source --network sepolia --contract Proxy
{
  "bytecode": "0..0",
  "abi": [ ... ]
}

$ npx synthetix suspension-reason --code 2
Market Closure

$ npx synthetix synths --network sepolia --key name
["sUSD", "sEUR", ... ]

$ npx synthetix target --network sepolia --contract ProxySynthetix
{
  "name": "ProxySynthetix",
  "address": "0x322A3346bf24363f451164d96A5b5cd5A7F4c337",
  "source": "Proxy",
  "link": "https://sepolia.etherscan.io/address/0x322A3346bf24363f451164d96A5b5cd5A7F4c337",
  "timestamp": "2019-03-06T23:05:43.914Z",
  "network": "sepolia"
}

$ npx synthetix users --network mainnet --user oracle
{
  "name": "oracle",
  "address": "0xaC1ED4Fabbd5204E02950D68b6FC8c446AC95362"
}

$ npx synthetix versions
{
  "v2.0-19": {
    "tag": "v2.0-19",
    "fulltag": "v2.0-19",
    "release": "",
    "network": "mainnet",
    "date": "2019-03-11T18:17:52-04:00",
    "commit": "eeb271f4fdd2e615f9dba90503f42b2cb9f9716e",
    "contracts": {
      "Depot": {
        "address": "0x172E09691DfBbC035E37c73B62095caa16Ee2388",
        "status": "replaced",
        "replaced_in": "v2.18.1"
      },
      "ExchangeRates": {
        "address": "0x73b172756BD5DDf0110Ba8D7b88816Eb639Eb21c",
        "status": "replaced",
        "replaced_in": "v2.1.11"
      },

      # ...

    }
  }
}

$ npx synthetix versions --by-contract
{
  "Depot": [
    {
      "address": "0x172E09691DfBbC035E37c73B62095caa16Ee2388",
      "status": "replaced",
      "replaced_in": "v2.18.1"
    },
    {
      "address": "0xE1f64079aDa6Ef07b03982Ca34f1dD7152AA3b86",
      "status": "current"
    }
  ],
  "ExchangeRates": [
    {
      "address": "0x73b172756BD5DDf0110Ba8D7b88816Eb639Eb21c",
      "status": "replaced",
      "replaced_in": "v2.1.11"
    },

    # ...
  ],

  # ...
}

synthetix's People

Contributors

0xclem avatar 0xdomrom avatar 0xjocke avatar artdgn avatar barrasso avatar cgewecke avatar davidvuong avatar dbeal-eth avatar dependabot[bot] avatar drptbl avatar hav-noms avatar i-stam avatar industrialist avatar jacko125 avatar jjgonecrypto avatar k-ho avatar k06a avatar kaleb-keny avatar leomassazza avatar liamzebedee avatar mjlescano avatar mjs-12 avatar mjspain12 avatar navp4l avatar noahlitvin avatar sohkai avatar theethernaut avatar thekevinbrown avatar zdary avatar zyzek 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  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

synthetix's Issues

Create an arbitrage contract for the sETH/ETH Uniswap Pool

The Synthetix foundation is running a trial to reward arbitraging the sETH/ETH Uniswap pool if the ratio falls below 99/100. The foundation is funding this arbitrage pool with 144k SNX initially during the trial. We need someone to write a contract that enforces the arbitrage pool mechanism on-chain without manual intervention.

The contract will:

  1. Allow a user to send ETH to the contract if the sETH/ETH ratio is below 99/100 &
  2. there is sufficient SNX remaining in the contract at the current exchange rate
  3. Convert the ETH to sETH via Uniswap up to the 99/100 ratio or the ETH is exhausted
  4. Convert the sETH to SNX at the current exchange rate
  5. Send the SNX to the wallet that sent the ETH

The sETH/ETH ratio can be read directly from the Uniswap contract, but the SNX/ETH ratio should be read from the Synthetix exchange rates contract on mainnnet.

We expect the contract to be deployed to Ropsten/Kovan testnet and tested with your support before the foundation deploys it to mainnet.

We do not require a front end for this contract as it will eventually be integrated into our Mintr dApp.

Resources and links:

Arbitrage Pool Announcement
sETH Uniswap Pool Contract Address
Synthetix Discord
Synthetix Dev Portal

Sirius Release: SIPs 16, 17, 18, 19 (26/09/2019)

This Thursday (AEST), we'll be deploying a new system upgrade to launch some of the recently approved SIPs. We will be taking down the system for several hours to deploy this release. During this time, users will be unable to interact with the system in any way, including using Mintr or Synthetix.Exchange, and transferring SNX or Synths.

Due to SIP 17, this release will also result in liquidity providers for the old sETH pool on Uniswap having their sETH frozen (as announced here). If anyone does not withdraw their liquidity in time, we will work with them to provide a solution.

Here's what will be included in this release:

  • SIP 16: Synthetix upgrades currently take longer than needed as the owner account makes up to 60 calls to configure the system. Most of these calls are setSynthetix and setFeePool on all of the Synths. We propose to point the Synths to the Synthetix Proxy and FeePool Proxy. This would reduce the amount of time the system is offline. Making upgrades a lot faster, cheaper (gas) and minimize the impact on users with reduced downtime.

  • SIP 17: This update will upgrade the currencyKeys from Bytes4 to Bytes32. This will enable Synthetix to create new Synths with symbols longer than 4 characters. e.g. sATOM, sDEFI, which is not currently possible with currencyKeys type defined as Bytes4.

  • SIP 18: This will recover the $2.9k sUSD that is currently unclaimable by minters in the SNX fee address. This sUSD is from the period in which there was a transfer fee for sending sUSD.

  • SIP 19: The Synthetix contracts still have transfer fees written into them, from before we disabled transfer fees in February 2018. Removing that code will optimise reclaim bytecode size required for new features.

This release is called 'Sirius,' which like future releases is named after a star (in order of visual magnitude).

ArbRewarder: max_delay does not restrict transaction execution time

uint tokens_bought = uniswapExchange.ethToTokenSwapInput.value(eth_to_convert)(min_seth_bought, now + max_delay);

Because now is referenced within the ArbRewarder contract, its value will be set when the transaction is included in a block. And because ethToTokenSwapInput is called within the same transaction, it is always executed within the same block. Therefore, the addition of max_delay does nothing to restrict the actual execution time of the transaction.

Please correct me if I am mistaken.

Hack Idea: Multicurrency Mintr

Fork Mintr to add support for every currency via a dropdown selector. Once selected all of the values will be denominated in the selected currency allowing you to burn/mint/claim fees in that currency.

Hack Idea: Debt Tracker

Build a dashboard to track the debt of a wallet over time vs the synth balance over time to see net performance of each wallet.

Direct Redemption & Liquidation of locked collateral

Holders of Synths would be able to redeem their Synths against synthetix / crypto collateral that are staked, if the minter is below the liquidation ratio, at a fair discounted value.

Problem

Direct redemption is needed as a monetary policy in order to protect the system from becoming under-collateralised in the event that the SNX value drops.

Synthetix would not be able to reduce the large buffer currently required (over collateralised to 750%) without a forced liquidation mechanism. Reducing the collateralisation buffer of SNX collateral to less than 500% will greatly increase the capital efficiency of the platform in the future. In order to achieve this goal it would require force liquidation of debt positions that fall below a threshold, in order to protect the system from going under-water (where total value of issued Synths is greater than all collateral).

Redemption mechanism

  1. Allows bearers of Synths to burn synth debt on behalf of another minter and redeem underlying collateral.

  2. Provides instrinsic value to synth debt for anyone who holds synths as backing it with synthetix collateral that can be redeemed at fair value.

  3. Dis-incentive for minters of synthetic debt to sell below par value of the synthetic asset on exchanges as they will need to pay a higher value to buy-back the synths for paying off debt if they are being liquidated.

  4. Stakers above the collateral ratio can protect their value in the system by liquidating another staker’s collateral that is below the liquidation ratio, to fix network’s collateralisation ratio.

  5. Incentive for users to keep network collateral ratio healthy by providing a discount on the liquidated synthetix collateral price.

  6. Minters who are being liquidated, can either buy back the synths on market to fix their collateral ratio, or allow others to do so but at a penalty.

Abstract

In a crypto-backed stablecoin system such as Synthetix, the issued stablecoin (synths) tokens should represent a claims on the underlying collateral. The current design of the Synthetix system doesn’t allow holders of synths to directly redeem the underlying collateral unless they are burning and unlocking their own synthetix collateral.

The value of the synths issued in the synthetix system is derived from incentivising minters to be over-collateralised on the debt they have issued and other economic incentives such as exchange fees and SNX rewards.

If a minter’s collateral value falls below the required collateral ratio, there is no direct penalty for being under collateralised, even in the unlikely event where the value of their locked synthetix collateral is less than the synths debt they owe. Stakers and synth holders should be able to liquidate these minters at a discounted price to encourage a purchase of synths debt in order to close off the minter’s position.

It would encourage minters to be above the required collateral ratio and creat economic incentive to buy-back synths on market to fix their collateral ratio if they are at risk of being liquidated.

Implementation

  1. Provide a liquidation contract for synth holders to mark a SNX staker as being listed for liquidation but give time (48 hours) for them to fix collateral ratio / burn debt by purchasing on market.

  2. Time delayed liquidation of under-collateralised collateral. Immediate liquidation is possible if SNX collateral falls below a critical threshold (ie, less than 120%) that should cover the debt and discount required.

  3. Prevents black swan events where malicious actor quickly dumps a sizeable amount of SNX on CEX’s / exchanges to push the price down suddenly and target liquidation, as there is a time delay for liquidation.

  4. Liquidator able to burn synths in exchange for SNX collateral at discount rate (% of the current value) as a penalty for under-collateralised staker.

  5. Liquidator pays off debt owed by a minter and minter gets balance of collateral returned minus a discount amount that is rewarded to liquidator.

  6. Other collateral asset types can have separate liquidation thresholds and time frames for redemption if under-collateralised.

SNX Staking Pool

Staking SNX is a fairly complicated process with numerous strategies to optimise yield and reduce risk. There are a number of community members who have put significant effort into optimising these strategies, particularly Nocturnalsheet. The effort and skill required to optimally stake SNX presents an opportunity for staking pools managed by community members with fee structures based on performance. There are several custodial staking pools considering SNX integration including EON and Staked, however, we believe there is an opportunity for non-custodial pools.

We need a contract to be written that supports the following functionality:

General features

  • Tracking of pool percentage via liquidity tokens
  • locking the contract calls to whitelisted functions/addresses

For pool participants

  • Depositing of SNX
  • Withdrawal of SNX
  • Withdrawal of staking rewards

For pool managers

  • Mint/ burn with pooled SNX
  • Collect fees
  • Deposit to depot
  • Deposit to Uniswap sETH pool
  • Call exchange on SNX
  • Set fee structure % of fees, or % of SNX staked or some combination of the two

*because staking rewards are escrowed for a rolling 52 weeks against the pool contract, in order for a depositor to withdraw reward SNX escrowed in the RewardsEscrow Contract https://etherscan.io/address/0xb671F2210B1F6621A2607EA63E6B2DC3e2464d1F,
the StakingPool needs a mapping to track the SNX rewards that the depositor is eligible for, so when the Pool Manager calls RewardsEscrow.vest() and the escrowed SNX rewards for the vesting period is sent to the StakingPool contract the the depositors can withdraw their allotment of the SNX rewards from the StakingPool.

*There should be some protection considerations for if the PoolManager has lost key access / gone AWOL

  • that potentially a depositor can call StakingPool.vest and it proxy to RewardsEscrow.vest() and get only their SNX allotment.
  • a depositor can withdraw their SNX at any-point causing the contract to do the appropriate Synth burn to release their SNX

Deliverables

  • Smart Contracts StakingPoolFactory & StakingPool
  • Working environment on TESTNET (Contact us for TESTNET SNX)
  • Unit tests using truffle and JavaScript tests. See https://github.com/Synthetixio/synthetix

Associated Bounties | links will be posted soon
Deployment dApp so a pool manager can configure and deploy a new pool.

A dApp that displays all active pools, including the fee structure and performance. Allow users to deposit/withdraw into pools.

Hack Idea: DAI Depot

Create a version of the sUSD Depot that accepts DAI for sUSD rather than ETH.

Users should be able to deposit sUSD into the contract and receive DAI.

Double the exchange rate on going short <> long.

I propose to temporarily double the exchange rate on any swing trade. That is any move to or from an "s" Synth to an "i" Synth.

Motivation

There is already a leveraged benefit on the inverse Synths and currently being able to trade short <> long in a volatile market is a continuous advantage to front runners.

This is only a temporary stop-gap until the full implementation of sip-12 is rolled out then I propose to remove this doubled exchange fee on going short <> long.

Implementation

Simply double the ExchangeRates.exchangeFeeRate(), currently set at 50 bips but usually 30 bips.
on any exchange to or from any synth beginning with s or i.

Exchange UI error: call exception

it seems the data on https://synthetix.exchange aren't loaded anymore, I get this error

1.cafdaec4.chunk.js:1 Uncaught (in promise) Error: call exception (address="0xba34e436C9383aa8FA1e3659D2807ae040592498", method="rateIsFrozen(bytes4)", args=[{"0":105,"1":66,"2":78,"3":66}], version=4.0.27)
    at Object.n [as throwError] (1.cafdaec4.chunk.js:1)
    at 1.cafdaec4.chunk.js:1

Hack Idea: Depot Upgrade

Write a contract to allow people to deposit sUSD or other synths. Issue a DEPOT token against each deposit in proportion to the value of the deposited synths, similar to the Uniswap LP token.

As people purchase from the pool ETH accumulates in the contract and can be claimed by burning DEPOT Tokens.

Hack Idea: Synthetix Alerts

Mobile app or email/sms service that sends triggered notifications when you should mint or burn and fee claim reminders at the start/end of each period.

Add Synth Exchanges to Uniswap

Synthetix has launched a number of unique assets over the last six months, but the learning curve on synthetix.exchange is still fairly high. In order to make the full range of Synths more accessible we want to launch a fork of the Uniswap UI to enable any Synth to be purchased directly from the Uniswap interface. Uniswap is one of the most popular DeFI projects and thousands of users are now comfortable using it to access liquidity across a wide range of tokens. By making all Synths accessible in the Uniswap UI we will significantly expand the audience for Synths in the immediate term. Once users are comfortable holding Synths they may decide to test out synthetix.exchange, but even if they only ever trade Synths on Uniswap the Synthetix contract will still capture exchange fees and pay them to SNX holders.

In order to complete this bounty we need the following:

  • Write a contract to atomically convert ETH -> sETH -> Synths
  • Fork the Uniswap UI and add all Synths
  • Write unit tests for all functionality

User Journey One:

  1. User hears about a new Synth sCEX and wants to hold it
  2. User navigates to Uniswap.synthetix.exchange
  3. User selects ETH - > sCEX
  4. User selects amount of sCEX
  5. The contract converts ETH to sETH via the Uniswap contract
  6. The contract converts sETH to sCEX via the Synthetix contract
  7. The user receives sCEX in their wallet

User Journey Two:

  1. User holds sCEX and wants to convert to ETH
  2. User navigates to Uniswap.synthetix.exchange
  3. User selects sCEX - > ETH
  4. User selects amount of sCEX
  5. The contract converts sCEX to sETH via the Synthetix contract
  6. The contract converts sETH to ETH via the Uniswap contract
  7. The user receives ETH in their wallet

User Journey Three:

  1. User holds sCEX and wants to convert to iCEX
  2. User navigates to Uniswap.synthetix.exchange
  3. User selects sCEX - > iCEX
  4. User selects amount of sCEX
  5. The contract converts sCEX to iCEX via the Synthetix contract
  6. The user receives iCEX in their wallet

Deliverables

Smart Contracts AtomicSynthetixUniswapConverter
Working environment on TESTNET (Contact us for TESTNET SNX)
Unit tests using truffle and JavaScript tests. See https://github.com/Synthetixio/synthetix

Triggered Order Contract

Triggered Orders Contract

Synthetix.exchange has many advantages over order book DEX's, a wider range of assets and with much deeper liquidity, but it is missing a critical feature in triggered orders. sX does not currently support any order type other than real-time market orders. We want to allow users to be able to set stop loss, take profit and limit orders. Once these basic order types are implemented we would like to expand the order types to more exotic orders, like trailing take profit, stop limit, partial stop loss and others.

User Stories

Create Triggered Order

  1. User comes to sX and sees option to setup triggered orders
  2. Dapp allows user to sign transaction delegating exchange functionality to the Triggered Order Contract
  3. Using sX user specifies triggered order. Params: currencyKeyFrom, amount, currencyKeyTo
    3.1 Limit BUY - BUY 50K sBTC @ sUSD $10,000
    3.2 Stop Loss - SELL 100 sETH @ sUSD $200
    3.3 Take Profit - SELL 500 sBNB @ sUSD $40
  4. User prepays ETH gas fees (Payable function on TriggeredOrder) with setting the limit order
  5. Dapp calls Service API with Triggered Order params saved in mongoDB
  6. Service listens to payable function storing the users gas(ETH) paid against the address

Execute Triggered Orders

  1. Service listens to ExchangeRates Smart contract for the UpdateRates event. If any rate changes tigger any open orders in the database then the Service will call a function on the TriggeredOrder Smart Contract to execute the exchanges on behalf of the user.
    1.1 The TriggeredOrder Smart Contract will refund the admin caller the amount of ETH it cost to run the call + a 10% fee

Edit/Cancel Triggered Orders

  1. sX has Triggered Order screen to see all orders open/executed/cancelled
  2. User can cancel, amend any open order

Implementation

In order to implement triggered orders on sX we need several new systems to be implemented. The team will implement the ability to delegate the exchange call to a contract. This bounty covers the following:

  1. Write a Triggered Order Smart Contract that allows an off-chain service to send a transaction to the execute the delegated orders on the Synthetix smart contract
  2. Write the off-chain service to monitor the exchange rates contract and trigger orders based on exchange parameters specified by users
  3. Integrate the delegation functionality into sX Dapp
  4. Allow users to pre-pay gas for their triggered orders
  5. Update sX to accept triggered order parameters from users and store in off-chain DB
  6. Include writing unit tests
  7. We expect the contract deployed to Ropsten or Kovan for testing with your support, and then deployed to mainnet, again with your support. We expect the changes to sX to be written as a PR to be merged and deployed to staging for testing by the Synthetix team with your support.

Replicate http://eips.ethereum.org for Synthetix SIPs

Synthetix is transitioning to a decentralised governance process. One critical component of this are the Synthetix Improvement Proposals. We replicated the EIP process for SIP with some minor modifications, and so we would like to implement a similar site to http://eips.ethereum.org for SIPs that will display all SIPs by status allowing for easier discussions in discord and during our governance calls.

This mini site will replicate the functionality of http://eips.ethereum.org displaying all SIPs and SCCPs from the SIPs repo using Jekyll or a similar tool.

The site will use the structure and workflow from SIP-1

For more info on the EIP setup created by Hudson Jameson see this reddit post

Trading and referral incentives

Something we have previously been concerned about is the fact that centralised exchanges have a range of incentive mechanisms available to them that DEXs are not able to implement due to Sybil attacks.

One example is a signup or referral bonus. If we were to allocate a bonus (something we have considered in the past) of sUSD for new users to trade with when they first start using sX, this would likely be exploited by attackers creating multiple wallets and doing whatever was needed to meet the minimum to qualify and extracting these incentives adding significant cost to the programme.

A recent discussion in discord with Boomshiki opened up a potential solution to this issue.

From Boomshiki:

By method of incentive, affiliate programs provide an attractive way to promote services to an audience. It can reasonably be assumed that any outreach stemming from affiliates should increase Synthetix marketing value, while rewarding promoters fairly. All around such a program would be mutually beneficial to referrer, referral, Synthetix (through increased brand awareness) and participants in the network (stakers) from increased usage of the sX.

Some issues to explore remain. Namely the attack surface Sybil poses, and mechanics in which risk of such can be reduced or made too costly to generate a net gain. Possible to such a degree for an attack to benefit the network. Additionally, incentives distributed to the affiliate pool and the percentages both referrer and referral receive need to be taken into consideration as any percentile taken from the fee pool would have effects on global debt and rewards.

The proposed solution is to implement a trading incentives pool, this would be funded by SNX from the inflationary rewards. Each week a percentage, say 5%, of the weekly inflation would be put into a pool to pay trading incentives. These incentives would be paid out to traders based on the trading volume on sX from that week. In addition traders who refer new traders to the platform will have 10% of the trading volume from the traders they refer added to their trading volume.

One challenge with these kind of referral and affiliate programmes is that users can refer themselves. We would reduce this attack vector by requiring that a user have been actively trading for at least two weeks before referring new traders. To incentivise users who were referred to actually complete the process a new user who is referred will get a bonus if they actively trade for a certain period.

When a new trader arrives on sX for the first time we will ask them to sign a tx linking their wallet with the wallet of the user who referred them. This tx will not be reversible, so once it is confirmed it is locked. We will then calculate the total volume on the exchange for the week and divide it amongst all active traders. We will likely set a threshold of ~$1k in weekly volume to qualify to ensure we do not need to send dust to accounts.

The system will work something like this:
Five traders each doing $10k of weekly volume
Each week they each get 20% of the trading incentive pool
One trader refers a friend who does 50k weekly volume
The next week the original 5 traders get 10% of the rewards and the new trader gets 50%, however, the trader who referred the new user also gets allocated 10% of the trading volume from the new user. So now the distribution is:
New trader: 50k
Trader 1: 10k
Trader 2: 10k
Trader 3: 10k
Trader 4: 10k
Trader 5 (referrer): 10k + 10k bonus

So rewards are distributed:
New trader: 45%
Trader 1: 9%
Trader 2: 9%
Trader 3: 9%
Trader 4: 9%
Trader 5 (referrer): 19%

If the new trader continues trading for x weeks they will get a bonus in week x+1, say 10%. This increases the cost of sybil attacks while still incentivising new users to actually put their referrer in when they start trading.

One of the issues with this system is that pure affiliates who do not trade will be somewhat disincentivised to participate. This may not be an issue initially as we will be looking to engage actual traders rather than affiliate networks, but could become a problem that must be addressed later if we want to expand the referral programme to non-traders who run educational or review sites.

TLDR:
A trading incentive pool will allow traders to earn SNX by trading on the platform, and will also allow us to create a fair referral programme that is reasonably sybil resistant and has well aligned incentives.

I have likely not anticipated every attack vector here, so any feedback or improvements are most welcome.

Decentralized oracles with Chainlink

Problem

The current Synthetix (SNX) oracle is a centralized point of failure. It runs constantly, reading in prices from a range of real-world pricing services and updates the ExchangeRates contract (currently at 0x99a46c4 at this time) with the latest prices for all of the assets underlying each of our synths (priced in USD).

The code for the SNX oracle is closed-source and centralized. It is closed in order to prevent bots from calculating differences in prices off-chain and profiting from delays in Ethereum transaction latency. It is centralized and managed by the Synthetix team, and while vigorously monitored and maintained, has significant centralization risk, with users forced to trust the team, their processes and integrity.

Proposal

To migrate to a decentralized oracle solution for all of our synths. The most robust solution available with the highest level of community engagement is the Chainlink ecosystem of pricing networks.

We propose to enter into agreement with Chainlink, upgrading our ExchangeRates contract to using their pricing networks gradually.

However, in order to prevent front-running of decentralized oracle prices, there is a strict dependency on Synthetix first refactoring the exchange() functionality to a new queuing mechanism (more details below).

Terminology

The Chainlink ecosystem uses certain language around oracles and pricing that makes sense to incorporate into the Synthetix nomenclature.

  • An oracle is an instance of their Oracle contract that supplies a price for a single asset (ETHUSD, BTCUSD or AUDUSD say). Each oracle is supported by a node on the backend, who is paid in LINK for their services.
  • An aggregator is an instance of their Aggregator contract which aggregates requests to all oracles in its list, yielding a single aggregate price (the public property currentAnswer is the price multiplied by some power of 10 for decimal support) for the asset.
  • A network is a collection of oracles that provide the same price. It is served by a single Aggregator that can be read on-chain

For example, here is a visualization of the ETHUSD aggregation network: https://eth-usd-aggregator.chain.link/

image

  • It is a single network that provides the ETHUSD price
  • There are currently 19 oracles serving the network.
  • And, there is a single Aggregator contract which aggregates these oracles on-chain, yielding a single readable price for ETHUSD: 0x79febf6. The current price is Aggregator.currentAnswer (which is the current market price of ETHUSD multiplied by 1e8 for decimal support). The last block number used for any oracle update is updatedHeight. As per the contract's minimumResponses property, only when 14 oracles have returned a price for a request will the Aggregator update the currentAnswer and updatedHeight.

Implementation

To work with the Chainlink ecosystem, our ExchangeRates contract would need to be refactored.

Unlike our current oracle which pushes multiple prices updates simultaneously, Chainlink uses a one-price-per-contract approach for modularity and reuse purposes. We agree with this approach, though some light refactoring will be required so that our ExchangeRates contract knows where to find the price for each synth. It will need a mapping of synth keys to a Chainlink Aggregator for that pricing network (e.g. mapping(bytes32=>address)).

For inverted synths - such as iETH, iBTC et al - we propose reading the regular rate from the Aggregator and then inverting it in our ExchangeRates contract, as we do currently.

Cost Basis

Currently the Synthetix Foundation is paying both the API costs for real world pricing of assets and the gas costs of updating the ExchangeRates contract on-chain.

Moving towards decentralized oracles will offload these costs from Synthetix directly. Synthetix and Chainlink are working together to find a reasonable cost basis for ongoing upkeep of the various pricing networks for all synthetic assets used.

Considerations

Pricing networks

Since inception, Synthetix has been fairly flexible with trying out different synths. This will be marginally more difficult under a decentralized system as a price network needs to form and be available on mainnet for every new synth added to the ecosystem. This will mean more lead time for adding new synths to the system.

Index synths

For indexed synths - such as sCEX and the upcoming sDEFI which are a weighted basket of number of prices - we propose working with Chainlink nodes to do the weighted calculations off-chain and provide the pricing of our indexes on-chain directly. The alternative would be a pricing network for every price inside each index (if it didn't exist already), which would be too costly.

Concerns

Front-running

The current Synthetix system tackles front-running of SNX oracle updates by limiting how much Gwei an exchange can be performed with (see SIP-12). This works as the centralized SNX oracle can be guaranteed to ensure all oracle updates are performed with higher Gwei than the aforementioned limit.

With Chainlink's network of decentralized oracles, this cannot be guaranteed. However with a large number of oracles per price network, and the Aggregator taking the median of a minimum number of updates, front running a price network becomes marginally more complex.

Frequency of updates

The SNX oracle runs regularly and updates prices on-chain, ensuring that small price movements are tracked. If an on-chain price deviates by more than the current exchange fee (currently 0.5% but lowering back to 0.3% soon), we update it, preventing bots from taking advantage of the difference between on-chain and real-world pricing (what we refer to as "technical front-running"). Morever, the SNX oracle ensures that every price is updated at least once an hour - and if any price is more than 3 hours stale (configurable via ExchangeRates.rateStalePeriod), the system freezes.

Chainlink's pricing networks will target on a 1% price deviation and a heartbeat of approximately twice a day. While the slower heartbeat can be incorporated into our system, the larger price deviation would expose the system to an unacceptable amount of "technical front-running".

Dependencies

Thus, in order to migrate to the decentralized oracle system of Chainlink and not expose the system to front-running attacks mentioned above, a different mechanism of exchanging is required. What we propose is to overhaul the exchange() functionality inside Synthetix. Instead of exchanges happening immediately, they would be placed into a queue to be processed FIFO once prices for both the source and destination synths has been received. This introduces its own challenges (such as who pays the gas), but has the added benefit of supporting limit orders on-chain.

This queuing mechanism will be a prerequisite to migrating to a decentralized oracle service. Once applied, we can begin the transition to Chainlink's pricing networks, one synth at a time.

Hack Idea: sX Trade Tracker

Track the USD value of every trade made by a wallet and the overall portfolio balance over time.

Could use an interface like pools.fyi to show each trade and then a line chart to show performance/balance over time.

Penalty SIP

The gist of the proposal is to enable instant-maturation of newly emitted SNX in exchange for giving up some fraction of the matured SNX as a penalty. Suppose a Mintr collects 10,000 SNX in staking rewards and wishes to sell them for ETH.

By electing to instant-mature SNX staking rewards, a mintr gives up for example 7,500 SNX and gains the ability to liquidate the remaining 2,500 SNX or otherwise do as they please with the SNX.

The 75% penalty / 25% unlocked ratio is somewhat arbitrary. The point is that if you want to dump SNX rewards, you should have the ability to do it, but there is a severe penalty.

Excessive SNX dumping exerts downward pressure on the price of SNX, which can lead to a vicious pattern:

  • SNX price depreciates
  • Mintrs burn sUSD to update the collateralisation ratio, which means a decrease in the total number of Synths in circulation
  • The level of fees generated for SNX Mintrs falls because fewer synths are being traded
  • sUSD rewards decrease

The 7,500 SNX are then funneled back into the inflation pool, where they will be claimed by other mintrs during the next fee period. This part of the mechanism functions essentially the same as how rollover rewards work, where unclaimed SNX staking rewards are recycled to become claimable by active mintrs in subsequent fee periods.

Genesis of the proposed Penalty SIP

SNX Staking Rewards are locked for the first year when inflation is 75% of total supply, i.e. supply of SNX tokens increases from 100 million to 175 million. Currently, the 1.44 million SNX emitted into circulation each week go into the wallets of Mintrs who are able to stake these SNX and mint more sUSD, but the new SNX can only reach the market after a 12 month maturation period.

Hobo Joe - SNX PermaBull suggested the idea for the Penalty SIP on the Synthetix Discord trading channel.

Open Questions

  1. With four months left until the end of the first inflation year, is building this functionality and then sunsetting it worth it?

  2. What should the penalty rate be set at for instantly-maturing SNX?

  3. Should all SNX be assessed a penalty with the instant-maturation option, or only those SNX a mintr has earned as staking rewards?

Considerations
With Mintr V2, the number of locked and transferable SNX is simple to visualize. With this knowledge, one mechanism for taking partial profits on SNX price appreciation is to unstake your whole stack, go to Uniswap, and sell whatever number of SNX you have earned as rewards from the original stack. With this route, you capitalize on the fact that maturing SNX can be staked as soon as they are claimed. This is a rough proxy method for selling SNX staking rewards.

Inserting an instant-maturation mechanism adds a layer of complexity. There may be unplanned attack vectors that disclose themselves with time.

With respect to question 2, my sense is that the penalty should be severe enough to discourage exercising the instant-maturation feature, i.e. at least 50%.

Mint, Burn and Claim in any Synth

Mintr Version 2 is live with bunch of enhancements and customer friendly short-cuts.
Synthetix, its dApps and Synths attract more users with increased awareness.
In the beginning, Synthetix Team limited the mint/burn/claim functions with sUSD only. However, there was always an option for sophisticated users to use the contracts to mint/burn other Synths straight away without using sUSD as an interim Synth.

Platform is at scaling stage and removal of frictions will speed up the adoption.

In this issue, I propose the following enhancement;

As seen from the current Synth distribution, most of the users are holding/trading various Synths. It is time for Mintr to support other Synths for Mint/Burn and Claim functions while still keeping the simple sUSD option available.

Mint Function:

Mintr to allow users to Mint any Synth directly.

ie. User stakes SNX and has $500 USD available to Mint. User chooses sETH, sBTC or other s and inverse Synths to Mint directly.

Burn Function:

Mintr to allow users to burn any Synth directly.

ie. User wants to Burn $500 USD worth of Synths. User chooses sETH, sBTC or other s and inverse Synths to Burn directly.

Claim Function:

Currently Exchange Fees can only be collected as sUSD. Mintr to allow users collect the exchange fees in any Synth directly.

ie. User wants to claim $500 USD worth of Synths. User chooses sETH, sBTC or other s and inverse Synths to Claim directly.

Fee Considerations

Currently, users directly Mint/Burn other Synths through contract, do not pay exchange fee. However, users interacting with Mintr interface to mint in other Synths follow sUSD => other Synths or the ones burning use other Synth => sUSD flow and generate transaction fees.

With this proposal, we need to decide whether transaction fee is applicable when a user Mint/Burn/Claim Synths, other than sUSD.

My recommendation is Minting or Claiming any other Synth should be consider as a trading activity and should have a transaction fee. However, Burning any Synth should be fee free.

sETH Pool Distribution Multisig and dApp

SIP-8 proposes to formalise the distribution of staking rewards to Uniswap Liquidity Providers in the form of SNX tokens diverted from the inflationary supply. In order to manage the process as proposed SIP-8 we need several elements.

  1. An m/n gnosis multisig with a distributed set of signers from the set of sETH liquidity providers.
  2. A dApp to allow:
    2a. Any signer to upload a CSV from the output of the sETH pool rewards validation script.
    2b. Each additional signer to verify the tx data payload to ensure it has not been modified from the output of the validation script.
    2c. Each signer to sign the tx once the payload has been confirmed as valid.
    2d. Each Uniswap LP token holder to verify the rewards to be distributed to them

We expect the contract deployed to Ropsten or Kovan for testing with your support, and then deployed to mainnet, again with your support. We expect each signer to be able to run the dApp locally for verification purposes, but a hosted dApp will be required to streamline the process for LP token holders. We can manage hosting/integration into mintr.

Gas Optimisation R&D

Gas Optimisation R&D
R&D on optimising gas usage on these upgradable contracts.

  • Synthetix
  • FeePool
  • ExchangeRates
  • Synth

This bounty is to create PRs into https://github.com/Synthetixio/synthetix/tree/develop
with each seperate optimisation.

Bounty

  • A bounty of 100 SNX for each 1% of gas savings.
  • Minimum of 10% savings must be reached to be valid
  • e.g 30% savings on Synthetix.issueSynths (100 * 30) = 3000 SNX

Functions

  • Synthetix.issueSynths
  • Synthetix.burnSynths
  • ExchangeRates.updateRates
  • FeePool.claimFees
  • Synthetix.exchange

Excludes

  • using solidity compilers optimize runs
  • ownerOnly functions

sDEBT Discussion

Many in the community have raised the idea for a Synth that mirrors the global debt pool. Since Mintrs see their individual debts go up when the global debt pool increases, one strategy is to hedge against changes in the debt pool by roughly mirroring the global distribution of synths on an individual basis.

For example, if sETH is 40% of the pool, sBTC is 5% of the pool, and the remaining 55% of the synths are sUSD, a Mintr might choose to allocate 40% of his Synths in sETH, 5% in sBTC, and 55% in sUSD. In fact this is the approximate distribution of all the synths in circulation.
Screenshot 2019-12-21 16 29 16
Source: synthetixstats.com

This is the mirroring strategy that Mintrs can employ to hedge against major changes in the debt-pool. This strategy requires an individual Mintr to rebalance his Synth allocation as the global distribution changes. If sETH goes 5x, the Mintr has exposure to this price growth and won't get rekt on his debt.

In another scenario where a Mintr who has a synth allocation of 100% sBTC, or 100% sUSD, and sETH goes 5x in price while sBTC and sUSD stayed flat, the Mintr will be strictly worse off, and will owe more debt than his synths are worth. See "Why does my total sUSD debt fluctuate over time?" for more examples and discussion.

Issue

Some members of the Synthetix community have therefore suggested: Why is there not an sDEBT Synth that automatically rebalances as the distribution of Synths changes? Some in the Synthetix Community, including the current author, believe this to be an unambiguously bad idea for the system.

sDEBT is untenable with the premise of the Synthetix peer-to-contract, pooled collateral model where Mintrs absorb the risk of debt fluctuations in exchange for an economic claim on fees generated by the Synthetix Exchange.

Summary of Discourse

  1. The sDEBT would be a negative expected value instrument, because it's unreasonable to think traders will lose on net before fees in the long term. You cannot expect to quote a market 24/7 and win prior to fees. That's just not how trading works. (Spreek)

I'm also not assuming that traders on net will be profitable. It's quite conceivable that they could lose money on net. A priori, there is nothing indicating that everyone else in the system that does not own sDEBT will be strictly off. right now a majority of synths are long BTC and ETH. If those two drop heavily, on average you'll see traders lose. (ZombieNik3)

It's theoretically possible but it defies common sense. Name me any market maker that quotes 24/7 with no spread. (Spreek)

Yes it does, because sDEBT's gains are the system's positive delta in debt, which is absorbed by the collective mintr base who doesn't own sDEBT. Unless under a few circumstances where you don't own sDEBT but still kill it in trading, and so are net better off anyway. (farmwell)

  1. If sDEBT existed - i'd mint completely to it and then just wait for the fees each week - I'm not providing any positive benefit to the system and get free reward. Just don't see it as a viable solution - I don't see why everyone wouldn't do the same meaning we would have no synths being traded. (Munter)

The sDEBT would need rebalancing at a transaction cost/fee to the system (cleese)

  1. I agree it doesn't make sense for the reasons already outlined around stakers being required to take on risk to be rewarded. However, one thing that could be interesting is if we provide some sort of sDEBT position that has a daily fee for holding it (or larger fee to enter/exit). That way, you're paying for the right to avoid the risk, and might provide an alternative system debt rebalancing mechanism, because there's the risk while people hold this sDEBT position, the system debt doesn't fluctuate (or even goes down), which means the people in the sDEBT position lose out due to the fees they paid to hold that position. (garth | synthetix)

Put a price on the right to avoid risk and sell it. feels like an insurance policy on first glance. Hmm. The value proposition of sDEBT evolves into: here’s an insurance policy to hedge against changes in the debt pool. (The people underwriting the insurance policy are the mintrs. This starts to feel like the value prop of being a mintr changes from providing liquidity as a pooled counterparty to being a claimant on fees without having to take on risk of your debt being repriced. If the premium is significant it feels like there may be an opening. The premium would be distributed to all mintrs who don’t hold sDEBT? Sounds trick implementation wise, just sell out of sDEBT at snapshot and claim fees paid by people holding sDEBT. (farmwell)

you could do it as rebalancing the sDEBT portfolio paying the .3% exchange fees every period
which is obviously theoretically doable for a bot currently, and we could let people do it and save some gas. but like I said, I would worry that it would be treated as an endorsement and cause people to lose money doing it (especially in a world without minter inflation rewards) (Spreek)

It still feels like a way to harvest inflation rewards while skirting the risk of debt repricing, and the issue there is now you are asking Mintrs to collectively underwrite Global synth debt changes as well as this weird index product that is itself a mirror of the global synth debt. There’s some second or third order effects I can’t quite wrap my brain around here atm. (farmwell)

I just think that it is fundamentally a zero sum game between the minter who wants to hedge all his risk on platform and all the other minters, so I don't really see a huge value proposition. (Spreek)

Like, if you can collect inflation rewards and be able to not lose on your debt, what’s the point of the inflation rewards? (farmwell)

yeah that's a good point. perhaps the high gas costs of implementing a hedging strategy are more of a feature to discourage it haha (spreek)

I don’t love the idea of becoming an insurance policy underwriter on global debt changes for not owning sDEBT, when as a mintr I already take on risk in the global debt balance fluctuating. (farmwell)

The oracle for sDEBT would be the debt itself. So I think it would create a circular reference. As debt goes up, sDEBT goes up, so debt goes up, ect. So you would eventually end up with with infinite debt and sDEBT. So implementing this synth would crash the crash the network with a p of 1, given enough time. I think. (deltatiger)

I thought the same @Deltatiger , but i screwed around a bit in excel and it looked like it was working.
I might have been doing something wrong though haha (Spreek)

Great discussion guys! A couple of points/thoughts.

I would be careful talking about insurance not to confuse things further. Everything in these type of enviroments is about allocating, pricing, assuming and handling risks. An insurance actor is someone who assumes risk and makes a business of handling that risk efficiently. Breaking things down to the different factors regarding risk is a better way to discuss not to get stuck in existing ways of thinking.

Regarding Circular reference issue from sDEBT. That is only a problem if you have a realtime, constant rebalancing. If you set up a periodic rebalancing (every 15 min, hourly, daily, or similar) it will not be an issue.

This whole discussion about sDEBT is actually not so much about the hedging feature against the debt-pool exposure but more around by whom, where and how such feature should be implemented. In order to bring this further I would need to start with better understanding of the foundational philosophy of Synthetix:
Is the vision of Synthetix to be a slim layer with features being created on top by third parties? Or does Synthetix want to provide more features/functionality itself?

I see risk allocation and handling as central part for the success of this product but implementation of such can be achieved in a number of ways depending on the foundational philosophy (cleese)

  1. Imagine an edge case scenario: all your mintrs buy sDEBT, and sDEBT open interest is greater than 70% of total Synths because it’s really popular among mintrs. Then you have a tiny minority of the mintr vase taking on all the risk of debt fluctuations. Not healthy.

Similarly it’s not the case that everyone could go into sDEBT and the system stays sustainable. Imagine another edge case where sDEBT open interest is really high. Now you have an index of the synth distribution that is itself greater in size than its underlying components, which opens up more oracle price arbitraging risk, because you can buy or sell against sDEBT based on how it’s going to be revalued in 15 minutes or an hour. So the self referentiality problem doesn’t go away, it gets worse the more you think about the product.

While it may be attractive from an individual perspective, the hang up for me is that it’s not the case everyone could buy it and the system is still better off. It would strictly shift risk from one group of users to another, and both groups get the same rewards for taking on different risk? Okay, but this will be fixed with a fee, to be paid how and at what rate? So non-sDEBT people get paid to take on the risk, that’s the only way it works, and it has to be so high you discourage most mintrs from doing it.

And the issue with the risk not being efficiently dealt with by non-sDEBT mintrs is exactly why this group shouldn’t be forced to underwrite the risk of global debt fluctuations for the collective mintr base. (farmwell)

  1. I would like to re-iterate - mintable sDEBT would NOT work, but a token representing the global debt allocation like an ETF could. (1053r)

  2. Dudes want to complain that sDEBT is a bad idea, yeah OK sure. Just make our own baskets then. (ZombieNik3)

Like I said, I don't have an issue with that, in fact in some sense it's the recommended strategy. (Spreek)

  1. You can't do it within SNX. Just think bout it. We would have to do it outside, like with Set Tokens or similar. (maex)

  2. Finally an explanation for the risks of sDEBT. (hearthouseflowerssquarequite)

Alternatives

  1. You could have an index token, similar to UNI-V1 tokens that represents sDEBT instead. This index token basically works like an ETF where user deposits sUSD inside, and it automatically purchases the various sX equivalent to the current global debt allocations while issuing a token (the index token) that represents the bought sX.

This index token can basically be then redeemed back into sX at any point in time (since there's no slippage but only transaction fees).

Of course the details for rebalancing of the index token allocation would then need to be ironed out. Ultimately, this is only going to increase fees across the network where hedgers are willing to pay for. (1053r)

  1. Someone can start an index fund call sDEBT and charge management fees. It's essentially the same as if the system has an sDEBT. (atosm)

Rinkeby faucet

By any chance is there any sort of faucet for Rinkeby?

I'm looking only for a sUSD faucet at the moment.

Thanks

Replace the SNX dashboard backend with The Graph

The Synthetix Dashboard is a web application that uses a closed source API to monitor and track transactions in the Synthetix ecosystem.

Blockchain analytics can get quickly get cumbersome and expensive. On Ethereum, events emitted from smart contracts are not available on public API services (such as Etherscan) and mappings (such as ones that track account balances) cannot be iterated.

The Synthetix team originally decided to create our own service to monitor and track transactions in real time as there weren't alternatives at the time that could supply our Dashboard the information it required. Since then however, the Ethereum ecosystem has evolved and developer tooling has increased significantly.

In an effort to continue decentralizing and opening up the Synthetix system, I propose we replace the closed system that supplies our Dashboard with one that is open source. And, in the spirit of open data and of removing trust, that the same system be queryable by anyone.

What is The Graph

The Graph is a decentralized protocol for blockchain queries on Ethereum. In essence, it supports GraphQL queries of entities. These entities can be created both when smart contract events are emitted and functions are invoked. Anyone can construct and query the user activity of the Synthetix smart contracts (see below). As a decentralized service, The Graph hosts its content on IPFS. Moreover, anyone can create additional subgraphs to be hosted alongside the one we manage.

Here's an example of using The Graph web explorer to query the Synthetix subgraph for sUSD transfers and SynthExchange events (and the underlying HTTP requests):

subgraph

Why The Graph

By exposing an API endpoint and allowing anyone to construct queries on our data, we allow anyone in the wider Synthetix community to verify, track, monitor, and report on our data in near real-time.

Concerns

As it stands, there are two longer term concerns with using The Graph:

  1. Processing times: In the past few months, we've noticed that the processing times of new versions of our subgraph have increased from a few hours to several days. This disrupts the develop-deploy-test lifecycle and creates a long turnaround for the entities to be refreshed. We have been talking with members of The Graph's engineering team who are actively looking into this.

  2. Cost: The Graph team have said that they plan on charging on a per-query basis in the future, yet their actual plans are unclear. They are VC-funded and in hyper growth mode, so as such are not charging for their hosted service right now. If they do decide to charge for hosting, we can look at forking their indexing service and using decentralized services for network and processing bandwidth.

Proposal

I suggest we move ahead and ensure the Synthetix subgraph can supply all the data required for our current Dashboard. Once done, we then cut over our Dashboard to use these feeds.

Uniswap 900K gas estimation fixing solution

Related issues: vyperlang/vyper#1091, Uniswap/v1-contracts#39

We suggest to move _emit call before tokenFallback to resolve Uniswap 900K gas estimation. Solidity passes 63/64 of gas in subcalls and now estimator increases gas until 1/64 of gas left is enough for _emit call.

Currently gas estimator is feeding Uniswap proxy until 1/64 of gasleft would be enough for _emit call.

Moving _emit before tokenFallback would decrease gas estimation to 100K instead of 900K

image

Audit remediation

Audit remediation

FeePool.sol: totalRewardsAvailable() function untested.
FeePool.sol: getPenaltyThresholdRatio() function untested.

Hack Idea: SynthetixScan

Create a tracker like etherscan/makerscan, where you can enter a wallet address see details of their Synthetix balances.

  • SNX balance
    - locked SNX
    - transferrable SNX

  • Synth balances

  • Wallet debt

  • Wallet c ratio

Overall network view:

Ability to sort wallets by total debt, c ratio etc

Track transfers/exchanges and other contract activity

Proposed sDEFI Index Synth weighting

sDEFI weighting

Here is the proposed sDEFI Index Synth weighting, determined according to current (31/10/2019) market caps. Please indicate support or rejection of this weighting using the emoji reactions.

Deployment needs to track historical sources and addresses

There are a number of reasons we might want this:

To track older contracts that are static with newer source code
A number of our source contracts have changed to keep them inline with the latest developments and yet they haven't been redeployed (usually because we can't - such as for eternal state contracts). E.g. SynthetixEscrow (nee HavvenEscrow) and SynthetixState. We'd like to have a way of knowing accurately which source solidity file is for which contract.

This will:
a) help us better simulate testing locally as we can simulate an upgrade
b) ensure our documentation is correct - https://docs.synthetix.io/addresses/ should show Solidity source and JSON ABIs for the aforementioned SynthetixState and HavvenEscrow rather than their newer sources as they do now which is inaccurate
c) help us document which contracts were modified in each deployment

To improve developer tooling on historical activities
A number of ABI changes have occurred to key user functions and events in Synthetix.sol. For instance, SynthExchange has migrated from bytes4 to bytes32 in Sirius (v2.10) with SIP-16. This means you cannot simply use the existing Synthetix ABI to filter on those older events in the EVM - you need the old ABIs for these.

This will:
a) help those building analytics tools to accurately query older Synthetix contract state
b) help us manage this same problem with our subgraphs - see https://github.com/Synthetixio/synthetix-subgraph/blob/upgrading-graph-cli/subgraphs/synthetix.yaml

To improve our release automation
Adding a version list file for each deployment target (mainnet, kovan, etc) along with the blocks introduced, SIPs added and entire list of contract targets.

This will:
a) help us show in our documentation which contracts were added and which removed in each deployment
b) help us automate official GitHub releases with links to SIPs addressed

Exchange Queuing Proposal

Problem

Currently when exchange() is invoked in Synthetix, the function is called with a source synth, an amount in the source synth, and the destination synth. The exchange is processed immediately given the current on-chain pricing in the SNX system. The code states:

  1. Burn the amount of source synth
  2. Calculate how much amount of source synth is in destination synth (amountReceived)
  3. Deduct a fee when required from amountReceived, updating it, and Issue an XDR synth for that fee
  4. Issue the amountReceived to the user in the destination synth

Step 2 above calculates the effectiveValue of amount in source to an equivalent in destination, given the current rates of exchange of both source and destination to USD in ExchangeRates.

An exchange itself does NOT impact the size of the debt pool in any way, as it is simply a repricing of debt - a conversion between from one synth to another. Yet when the prices of synths change from oracle updates to ExchangeRates - then the debt pool is affected.

The current SNX exchange mechanism works like a market order. The user is getting the current market price between source to destination, given the rates the SNX oracle has placed on chain.

This entire flow however, exposes front-running risk. As long as an exchange is mined before the SNX oracle updates, any knowledge of what will happen in the upcoming update can be profited from.

We are currently working around this with SIP-12, however this is only really a temporary fix to the problem.

Proposal

Instead of immediately processing an exchange, it is placed into a queue, along with the current blockHeight. This queue could be processed by anybody at any time, with the exchanges in the queue only filled when their source and destination are updated by an oracle. This then prevents any front-running for good.

This functionality would also support limit orders - allowing users to add orders to exchange when the rate between the source and destination reached a certain threshold.

Concerns

1. Processing the queue - who pays the cost

The obvious question is, who processes the queue, and thus who pays the gas? Each exchange costs around 200k in gas (exchangeGasUsage). Making the user transact twice - once to put it in the queue and once to process it - is too much friction.

Instead, we can create a function process() that anyone can call to process the queue and recover their spent gas costs in sETH. This amount should be the equivalent of tx.gasprice * exchangeGasUsage for each successfully processed exchange.

I propose that the payment of this come from the exchange itself, with a user-placed maxGwei cap on how much this fee can reach to prevent griefing attacks (where by malicious users invoke process() with enough gas to take significant portions of the exchange away from the exchanger).

To ensure the exchange volume is sufficient to pay the processing fee, I propose that for exchanges less than some configurable USD minThreshold amount, we allow them to be executed immediately, bypassing the queue. This alleviates the issue where small exchanges that can't afford their gas processing costs get stuck in the queue. This amount should be small enough that spamming the system with a large amount of these would not alllow profitability of potential front-runners when accounting for gas costs.

One downside of this approach is the added friction to the user who now has to add a maxGwei amount to their exchange. To mitigate the complexity of this, I suggest we prefill this amount in our dApps using the best estimates of current average & fast gas, helping them customize it if need be.

Alternate approach: Meta-transactions & relayers

An alternative approach to the payer concern is to set up something akin to the Gas Station Network (GSN), with a Relayer paying the gas costs. The upside of this approach is that users could sign meta-transactions to a relayer without paying a gas fee. The fee could then be deducted as with Option A) above.

The trouble with this approach is that the system needs to prove the user actually broadcast their meta-transaction at a specific block in order to ensure the delay of processing is legitimate. Morever, even solving for this, using a Relayer creates a point of friction where users cannot directly place their exchange on-chain but rather have to go through a Relayer in order to demonstrate a delay between when they placed an order. This adds more complexity to our dapps and prevents users interacting with the contracts directly using explorers like Etherscan and MyEtherWallet.

2. Reasonable timing

The next question is when is the queue processed? Or in other words, how long should a user expect to wait for their exchange to be executed (or their order to be filled, in the parlance of traditional order-book exchanges).

This is particularly important when using decentralized Chainlink oracles, which are targeting a twice-daily heartbeat. If a price does not move outside the 1% threshold, then it's possible to not receive a price in a 12 hour period. Obviously this is an inordinate length of time to ask any user to wait. To mitigate this, I propose we have some number of blockDelay, after which, an exchange can be processed, even when an on-chain price has not been received from an oracle.

While this does mean that users could still trade on price movements off-chain that have not been reflected on-chain, the profits they can make are negligble the longer the blockDelay is, given that price deviations at 1% or more would be broadcast.

Implementation

The Synthetix contract would need an array of QueueEntry items, along with a new addToQueue() and process() functions.

public minThreshold: uint = ...;
public gasPerExchange: unt = ...;

struct QueueEntry {
  address sender;
  bytes32 source;
  uint amount;
  bytes32 destination;
  uint maxGwei;
  uint block;

  // for limit orders
  uint rate;
  uint expiry;
}

QueueEntry[] public queue;

public function exchange(bytes32 source, uint amount, bytes32 destination, uint maxGwei) {
  if amount less or equal to minThreshold
    _internalExchange(source, amount, destination)
  else
    push new QueueEntry to queue
}

public function availableToProcess(gasPrice: uint): uint {
  return count of (filter queue where each item canProcess at gasPrice)
}

public function canProcess(item: QueueItem, gasPrice: uint): bool {
  return
    // ensure cannot surpass gas limit
    gasPrice less or equal to item.maxGwei AND
    // ensure price has been received or delay hit
    (
      source & destination rates are newer than item.block OR
      block.number is greater than item.block + blockDelay
    ) AND
    // ensure limit requirements if any
    (item is not limit OR item.rate is at or below current market rate and not expired))
}

public function process() {
  for each queue item
    if gasleft() less than exchangeGasUsage
    then
      return
    if canProcess item at tx.gasprice
    then
      gasFee = tx.gasprice * exchangeGasUsage
      execute exchange for (item.amount - gasFee) for item.sender
      execute exchange for gasFee from item.sender to message.sender in sETH
      delete item from queue

    // cleanup old limit orders
    else if block.number >= item.expiry
    then
      delete item from queue
}

Example

Let's say the minThreshold to use the queue is 5 sUSD total exchange size. And the exchangeGasUsage is 200k.

Now let's imagine we're at block 500 and the queue is empty. sETH is at the rate of 200, being last updated at block 450 and sBTC is at 8,000, last updated at block 495.

  1. At block 500 Alice invokes exchange for 5 sETH into sBTC, maxGwei = 5.

    At the time of the exchange, 5 ETH would be worth 1,000 sUSD, or 0.125 sBTC (for reference, the ETHBTC rate here is 200 / 8000, or 0.025).

  2. At block 501 Bob reads availableToProcess(gasPrice: 5) and it returns 0 as both the latest sETH block update is less than 500.

  3. At block 501 another user Christina submits an exchange for 1 sUSD into sETH. As it's below minThreshold, it is processed immediately.

  4. At block 504, sETH is updated to 205 by an oracle. The ETHBTC rate is now 205/8000. As Alice is looking to move out of (or selling) ETH, this movement is favorable to her.

  5. At block 505 Bob again reads availableToProcess(gasPrice: 5) and it still returns 0 (as sBTC is still stale).

  6. At block 510, sBTC is updated to 7900 by an oracle. The ETHBTC rate is now 205/7900. As Alice is looking to move into (or buying) BTC, this movement is favorable to her.

  7. At block 510, Bob reads availableToProcess(gasPrice: 5) which returns 1. Trying availableToProcess(gasPrice: 5) returns 0.

  8. At block 511, Bob invokes process() with a gasPrice of 5 gwei. The first and only entry in the queue is found as the source and destination have a higher blockHeight than the queue entry, so it is processed.

    • The cost of the transaction is calculated at 200,000 * 0.000000005 = 0.001 sETH (which is the equivalent of 0.205 sUSD, or 0.02%).
    • This leaves the exchange with 4.999 sETH. Subtracting the 0.3% exchange fee yields 4.985003 sETH (or ~1022 sUSD worth).
    • Alice has 5 sETH burned and is issued 0.1293317234 sBTC. Bob is issued 0.001 sETH. The fee pool is issued 0.014997 sETH at the equivalent XDR rate.

Hack Idea: Strategy Synths

Create a meta synth that follows trading strategies similar to the Set Protocol ETHMA tokens.

User chooses strategy deposits ETH to contract which is converted to sETH. The contract mints a token representing the strategy. The contract auto-rebalances based on certain triggers using Synthetix Exchange.

Need web3 query to get max_eth_to_convert, tokens_bought and reward_tokens

I'm looking into building some automation that calls arbSynthRate on the ArbRewarder contract. The first thing I'm wanting to build is a dashboard that shows the maximum input ether along with the tokens + reward. Maybe I'm missing it, but I'm not seeing a way to get this information out of the contract since most of the methods are marked private. For now, I'm essentially re-implementing most of the calls in my own code.

I think it would be very helpful if there was a function that had a signature something like this:

function arbitrageAvailable() public view returns (uint max_input_ether, uint synth_output, uint synthetix_reward);

Then, every time a new block arrives, I can use web3 to query arbitrageAvailable.

Am I missing a better way to do this?

I also want to say that this contract is my favorite example of permissionless defi composability yet. Awesome work.

Looking for some examples for how to curl the Synthetix API

Looking for some examples for how to curl the Synthetix API

Hi,

I am testing out the Synthetix API at the moment. I am looking for some examples for how to curl the API. If you could post a couple of examples below that would be nice.

BM

A Mechanism for Decentralised Proxy Contracts

If you don’t care about the context and just want to read about the mechanism, jump down to the Proposed Solution section.

Recently there has been some debate about the decision to use proxies for the Synthetix smart contract suite. While the decision was not made lightly, it has been a concern of mine for a while. Not because I believe our team to be malicious, but because I don’t want anyone using the system to need to even consider this before using it. This weekend while thinking about the issue I came up with a potential solution that I have not previously seen, it may have been proposed earlier though and I missed it. In any case, this post will offer a solution to the proxy contract issue, but first I will provide context on what a proxy contract is and why Synthetix uses them.

Introduction to proxy contracts

Smart contracts are intended to be trustless, which means that the code that is verifiable by anyone and that you can determine how the contract will behave when you interact with it. This doesn’t make smart contracts perfectly safe — there can still be bugs or other issues that can cause you to lose funds when interacting with them. But interacting with a smart contract should be deterministic. This is where the real power arises, because once deployed the contract treats every transaction the same.* So users are empowered to interact with the contracts without fear that they may be modified or captured, and this is obviously not true of other platforms where a central authority controls them and can change them at will.

Proxy contracts break this assumption, because they grant certain privileged parties the ability to change the behaviour of the contracts after they are deployed. But before we explore this let’s discuss how they do this.

There are a few different proxy contract architectures, but the basic one as described by Nick Johnson can be found here. Essentially it splits a standard contract into three parts, Storage, Logic and Registry (the “proxy”). By doing this we can deploy a new logic contract and tell the registry contract to connect to this new logic rather than the old logic. One of the immediate benefits of this is that the contract address for the proxy can remain the same but the logic can be upgraded.

So why would you want to break the assumption of logical immutability when dealing with a deployed smart contract? The answer is that it allows us to upgrade the contracts to improve the functionality. But the reality is that you can already do this fairly easily. You can just deploy an entirely new contract suite whenever you need to upgrade, then users can use a migration contract to convert their old tokens to the new tokens and take advantage of the new logic.

This is definitely a better solution from a security perspective, but it is simply not practical from a usability perspective for two reasons. The first is that if you are rapidly iterating on a system you may make 2-3 upgrades per year. This would require a token swap 2-3 times per year, which is a lot of friction for users. It also means you will likely have tokens spread across four or more generations of contracts for ever. The second reason it’s not practical is that it means external services must regularly update the addresses they use to contract to the contracts, which is even less practical.

The smart contract trilemma

With all this in mind, any smart contract project is presented with a trilemma: pick two from Usability, Security and Speed (of iteration). We chose usability and speed of iteration, but we believe this was the pragmatic choice for two reasons. The first is that you need to trust the team initially anyway. This argument is somewhat akin to the PoW miner collusion argument: yes, miners could collude and launch a 51% attack, but it would destroy their investment in mining equipment. Now, this is not a perfect argument, but in this case our view is that in the early stages it would be unprofitable for the team to collude to steal the tokens or destroy their value, especially (and I am just being frank here) when the treasury—which is the real value in the early stages—was already controlled by the team. But the more important point is that the trilemma can be flipped later! You can actually decide to replace Speed with Security once speed is less important. And this is a critical point. Speed of iteration is so much more valuable than security early on in a project’s life that without it you are seriously lowering the expected outcomes for the project, so increased trust is a false promise.

OK, so two questions follow from this argument, the first is when do you flip the trilemma and more importantly how?

Let’s start with when. Personally, I believe you do it when the community demands it. But you can also do it slowly rather than all at once. There are numerous bridges in the Synthetix system that can be cut to remove privileges from the engineering team. I think we are getting close to a point where we need to start doing this. To that end we will be releasing a roadmap for the second half of the year and it will lay out the aspects we intend to make immutable. There is obviously risk here, in that if something goes wrong we will be forced to use the token swap route, but that is not the worst fallback to have.

So now, finally, to the point. Apologies for so much context, but I think these kinds of decisions need to be viewed holistically rather than in isolation. For more context on my approach to decentralisation see this article.

Proposed Solution

The fundamental issue with the proxy design is that the owner of the proxy can replace the logic contract with arbitrary logic of their choosing. In practice the owner is usually a multisig or some other mechanism that requires multiple parties to sign the transaction. But in practice this not really going to prevent the system being captured. So I am proposing a solution that uses a signalling contract as the owner of the proxies. This contract will serve two purposes. The first is that it will send the transactions required to rewire the proxy contracts, thus replacing a multisig controlled by several individuals. The second and more important function is that it will allow anyone to send a transaction that specifies a proposal to rewire the contracts to new logic contracts. This is important as it means there is no privileged owner of the system. Anyone can propose a change and that change can then be voted on by token holders. Now some of you (Vlad Zamfir) are probably screaming “on-chain governance: burn it!” But we are essentially just replicating the previously discussed token migration method for upgrades. Not perfectly, of course, because if you vote against the change then the upgrade could still take place, but in the scenario where you elect to not migrate your token it will most likely become worthless, but if everyone chooses to not migrate then the upgrade will essentially not proceed until the issues are resolved.

Open Questions

There are some questions here of course around the actual implementation, specifically how will voting work. I have some initial thoughts but I think that some threshold must be set whereby if after a certain period some percentage of tokens have not signalled to change then the upgrade is rejected. Of course you could say “well, no one will vote!” But I am inclined to disagree because this is not the same thing as a vote to spend funds in a DAO where non-voting is unlikely to impact you. In this case, if you don’t vote then the upgrade doesn’t proceed, which will likely have an impact on the value of your tokens. But we also have the option of forcing users to vote before they can claim fees, given that more than 80% of the outstanding tokens claim every few weeks this would be extremely effective in ensuring voter turnout.

There are other solutions like quadratic voting, which while potentially subject to sybil attacks is less of a concern in the Synthetix system, due to the staking mechanics where users have to stake and they earn rewards that are escrowed but can be used to earn further rewards. This means that if you split your tokens into multiple wallets you will then have to manage those fragmented wallets, which has a high cost in both gas and effort.

In any case the specifics of the signalling mechanism are probably less important than the fact that with this architecture you end up with slightly reduced security (the contracts are not immutable) for slightly slower iteration speed (you need to build consensus for upgrades) and slightly more friction (you have to vote to signal your approval for a change). Given these adjusted trade-offs I think implementing a mechanism like this for Synthetix is worth considering and I will be writing up a SIP (Synthetix Improvement Proposal) for it shortly.

Ether Collateral

Adding Ether as a collateral option for Synths is a feature many in the community have requested. There are numerous reasons for this, but the predominant one tends to be that Ether is viewed as a safer form of collateral than SNX, and that by combining SNX and ETH as collateral within Synthetix the protocol will be more robust. Ether collateral also aligns with the social norm of implementing Ether into protocols where possible.

The original mechanism for ETH collateral would have allowed stakers to augment their SNX positions with Ether. However, this introduced several issues, including the potential dilution in the value of the SNX token destabilising the network. This risk is offset by the ability to scale the Synth supply faster and generate more trading volume on sX. So the question was whether the trade off of SNX value dilution in the short term was worth the long term benefits. This document proposes a mechanism that avoids this conflict.

The key to this solution was combining the proposed Synth lending functionality with the Ether collateral mechanism. The result is a system that augments the Synth supply, enables easier and more efficient access to sX and does not dilute SNX value capture.

The proposed mechanism works as follows:

Anyone can mint Synths by locking Ether
The total amount of ETH to be locked (in aggregate) will be constrained by the SNX market cap
or the outstanding Synth supply
The collateralization ratio for ETH will be between 110% and 150%
There will be a minting fee to lock ETH
There will be an interest rate charged daily (or at some other to be determined interval)
The interest rate will be calculated based on a tbd formula (potentially the ratio of ETH debt to SNX debt)
Only sETH can be minted by locking ETH
The debt position will be denominated in sETH
The minted sETH can be converted into any Synth
The debt will be fixed and will not fluctuate with the total debt pool
(this means debt changes will not impact the debt position of ETH minters only SNX minters)
The minted sETH will be calculated as part of the total debt pool
To unlock ETH the same number of units of sETH must be burned + any interest accrued
Locked ETH will not earn staking rewards
SNX stakers debt percentage will be calculated by taking the current total debt and subtracting the fixed sETH debt from ETH minting

In addition to the benefits listed above there is an additional benefit which is that the sETH issued through ETH minting is effectively a short on ETH, so this will offset the current long bias of the existing debt pool. This does mean that minting sETH is not a viable leverage strategy for ETH holders, it will only allow them to either hedge their ETH position or gain exposure to other assets. Once Synthetic positions are available this will change, as sETH can be used for leveraged sETH positions. This is similar to users of Bitmex who deposit BTC as collateral to open leveraged positions against their deposited BTC.

Open questions:
What should the C ratio be
What should the minting fee be (if any)
What should the debt ceiling be set to as a % of total debt
How should the APR be calculated on ETH collateral

Comments, questions and suggestions welcome. Once we have closed out some of the open questions we will spec this up as a SIP and put it into the queue to be implemented if it proves acceptable to the community and viable to implement. Special thanks to the Guardians and Nocturnal for providing feedback on the draft document.

Gas Opt - issueSynths / burnSynths directly via issuer contract instead of Synthetix contract.

Currently Synthetix contract is permissioned to invoke issueSynths and burnSynths on issuer.sol. However these functions can be invoked directly via the issuer contract instead of jumping through Synthetix first.

Synthetix.sol

function issueSynths(uint amount) external optionalProxy {
    return issuer().issueSynths(messageSender, amount);
}

function issueMaxSynths() external optionalProxy {
    return issuer().issueMaxSynths(messageSender);
}

function burnSynths(uint amount) external optionalProxy {
    return issuer().burnSynths(messageSender, amount);
}

issuer.sol

function issueSynths(address from, uint amount)
    external
    onlySynthetix
// No need to check if price is stale, as it is checked in issuableSynths.
{

Remove or override functions for access direct via issuer.sol

modifier onlySynthetix() {
    require(msg.sender == address(synthetix()), "Issuer: Only the synthetix contract can perform this action");
    _;
}

Tightening user incentives SCCP bundle

While the growth of Synthetix over the last few months has been incredible, there are still many aspects of the project that need significant improvement. We have discussed a number of these major architectural changes on the recent governance calls and they are critical to the success of the project, decentralised oracles being one example. There is a another category of change available within Synthetix, tuning parameters. This was the reason we separated SCCPs from SIPs to delineate minor parameter changes from protocol upgrades. This proposal will bundle a number of parameter tweaks I believe we need to implement in order to tune the feedback loops within the current system and align user incentives more clearly. The list of proposed changes are below:

  1. Reduce claim window to 1 week (SIP-9)
  2. Increase arb pool to 5% of weekly inflation
  3. Reduce the c-ratio buffer from 10% to 1%
  4. Increase the c-ratio to 1000%

  1. Firstly I think we need to revisit SIP-9. This SIP was rejected several months ago, however, but if we implement this SIP we will reduce the amount of leveraging sETH that we are currently experiencing. When someone sells down sETH into the market to go long other crypto they are taking a risk that they will not be able to claim fees in the next period without buying back the sETH/sUSD on market later if the price of SNX falls. The longer a user can delay the need to burn and bring their ratio back into alignments the lower the risk. We are now seeing a number of users claiming on a biweekly schedule, this gives them up to 20 days potentially to repair their c-ratio. This period is too long and has lead to a steady erosion of the sETH/ETH peg over the last few weeks. This issue was obfuscated due to the demand to enter the sETH pool, as this demand has declined the selling pressure on sETH has increased to the point where we are now below .97 sETH/ETH ratio. By tightening the claim window to 1 week we will force all minters to repair their c-ratio within 13 days maximum or lose rewards. One of the objections to this change in the past was the cost of claims. With gas prices hovering around 1 gwei recently and gas optimisations about to go live this argument is far less valid.

  2. The arb pool has been drained very quickly over the last few weeks. There are several reasons for this, the first is that some of the front-running bots are using it as a way of clearing out excess sETH profits they are holding. On the face of it this might seem like a less than ideal situation. But the reality is that the arb pool is absorbing excess supply directly that would otherwise be absorbed into the sETH pool itself impacting the peg. By increasing the supply to the arb contract we can more quickly absorb this excess supply of sETH and tighten the peg, in combination with proposal 1 to change the window where users can be undercollateralised without being penalised this should exert upward pressure on the peg.

  3. Another aspect of the system that allows users to remain undercollateralised indefinitely is the c-ratio buffer. This was initially required to avoid users being slashed by rapid price drops in SNX when the original mechanism reduced fees by 25%+ if a user claimed while undercollateralised. Given that now a user will only have a tx fail, the need for this buffer to be so large has been removed. By changing the buffer to 1% we should see relatively few failed claims due to SNX price shifts, while raising the global c-ratio by 10% during times of SNX price decline.

  4. Increasing the c-ratio to 1000% will help to rebalance the supply of Synths, there is still an excess supply of Synths in the market, and we have not yet seen demand catch up due to continued increase in SNX price. I do not think we will see a meaningful increase in Synth demand until we have several of the planned changes implemented, particularly the upgrade of sX to v2.0 planned for 4-6 weeks from now. During that time it is important that we realign supply and demand to restore the peg, raising the c-ratio has been an effective mechanism in the past and is likely to be effective this time as well.

The combination of these four changes is likely to be sufficient to restore the peg while we wait for the implementation of a number of protocol improvements over the next several months. It is important that we actively adjust the system parameters to reflect the current market dynamics and align incentives. These changes collectively should be extremely effective in doing so.

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.