SIP-303: Markets (V3)

NetworkEthereum & Optimism
ImplementorDaniel Beal (@dbeal-eth), Leonardo Massazza (@leomassazza), Alejandro Santander (@ajsantander)

Simple Summary

This SIP proposes the creation of markets in Version 3 of the Synthetix protocol. Markets are expected to accept sUSD, generate positions, and rely on liquidity provided by funds to back any debt inflation generated by their positions.


Markets are a generic abstraction that allow products (such as spot markets and futures markets) to be built on the protocol. Market contracts interact with the market manager to mint sUSD, burn sUSD, and interact with funds for liquidity. Markets can be designed and deployed by anyone.


By creating a generic market interface, we are able to cleanly separate concerns in the codebase and allow for greater composability with the protocol. Though we anticipate starting with implementations of futures and spot market contracts, it should be possible to design new types of markets for the protocol as well.



Markets interact with the market manager to read the amount of liquidity available to them and report the balance (debt or credit) they’ve generated. The market manager tracks the share of the balance apportioned to each of the funds that are providing liquidity to a given market.


By facilitating all of logic pertaining to minting and burning sUSD within the market manager, we’re able to allow the permissionless creation of markets in the protocol. The intention of this design is ensure that only the funds which back a given market are exposed to risk generated from this market, while keeping sUSD fungible and shielded from this risk.

In the worst case scenario, a malicious actor could generate a market, persuade funds to provide it with liquidity, and then set the balance value to a large negative number (suggesting large debt inflation). This would subject the funds involved to liquidation, but no other risk should be assumed by the protocol.

Technical Specification

The market manager will implement the following interface:

interface IMarketManager {
	function registerMarket(address market) returns uint;
	function setSupplyTarget(uint marketId, uint fundId, uint amount);
	function supplyTarget(uint marketId) returns (uint);
	function setLiquidity(uint marketId, uint fundId, uint amount);
	function liquidity(uint marketId) returns (uint);
	function fundBalance(uint marketId, uint fundId) returns (int);
	function totalFundBalance(uint marketId) returns (int);
	function deposit(uint marketId, uint amount) public;
	function withdraw(uint marketId, uint amount, address recipient) public;

Markets can be registered with the market manager using the registerMarket() function. This validates the presence of a balance() function in the specified contract and stores the address in a mapping (with an incrementing uint as the key). This function may also emit an event (for improved protocol analytics) or include various restrictions around market creation.

Each fund calls setSupplyTarget() and setLiquidity() in its rebalanceMarkets() function. This updates the supplyTarget() and liquidity() values for a market, which are the sum of each of these values being provided by each fund.

Each fund is responsible for a balance based on their proportional share of the supply target for a market. This is related to the market’s balance() and can be read from the fundBalance() function.

Markets can call deposit() to transfer sUSD into the system with the appropriate accounting. This would be used when someone provides sUSD to a market to purchase sBTC, for example. This function requires that msg.sender is associated with the specified marketId.

Markets can also call withdraw() to mint sUSD to the specified recipient. This will revert if the total amount of sUSD minted by this contract were to exceed the total liquidity provided to it. This function requires that msg.sender is associated with the specified marketId.

The only function that a market must implement is balance().

interface IMarket {
	function balance() view returns int;

A market must call registerMarket() on the market manager contract before interacting with it. Typically, the market would call it in its constructor method and store the returned id.

As an example, a basic synth spot market for sBTC could be implemented as follows:

  • An ERC-20 contract would be deployed, with a mint and burn function only callable by the market contract and a symbol() function that returns sBTC.
  • The sBTC market contract would be deployed with the following functionality:
    • balance()
      • Returns the total supply of the sBTC token multiplied by the current price of BTC, as a negative value.
    • mint(uint amount)
      • Transfers the specified amount of sUSD from msg.sender to market manager with the deposit() function.
      • Determines the exchange rate based on a price oracle and applies any fees.
      • Mints the appropriate amount of sBTC to msg.sender.
    • burn(uint amount)
      • Burns the specified amount of sBTC from msg.sender.
      • Determines the exchange rate based on a price oracle and applies any fees.
      • Transfers the appropriate amount of sUSD from the market manager the withdraw() function to msg.sender.

Note that if fees are simply deducted during exchange, they are effectively distributed among funds pro-rata based on the amount of liquidity they’re providing. This would be similar to stakers having their sUSD fees instantaneously burned in the current version of the protocol. Stakers mint sUSD to retrieve them.

Test Cases

Relevant tests will be developed during implementation.

Configurable Values (Via SCCP)

  • Approved Markets (address[]) - This is a list of market contract addresses owned (or otherwise approved) by the Spartan Council and will be listed in the official UI.

Copyright and related rights waived via CC0.