Introduction to SynFutures@v1 Architecture
After we settled on the idea of building an open and trustless derivative market, the next question is how such market can be built on-chain, where gas price might be high or proper price oracle might be missing. The mission becomes more challenging when we want to protect our users from various DeFi attacks, including the infamous flash loan hack, by introducing the widely adopted practices in the traditional financial market. In this blog post, we share with our readers the architecture of SynFutures@v1 and our thoughts behind the design.

Challenges with futures exchange
Compared with the battle-tested spot DEX Uniswap V2, SynFutures@v1 is also built to be permissionless and trustless, but with much more challenges as a derivatives exchange.
The current architecture of Uniswap V2 reflects the nature of spot exchange , where a market can be uniquely identified by two cryptocurrency assets, namely the base and quote assets, and required only one liquidity pool. By design, this market can always be active due to the combination of the constant product model and deliberately locking a tiny part of assets from the first liquidity provider for the pair . Combined with the multiple swaps provided by Uniswap router, one active spot exchange market of a digital asset pair is sufficient. This could be one of the reasons that Uniswap doesn’t resort to the proxy pattern when creating new pairs.
However, we are not that lucky with futures market. To begin with, a futures market is identified by not only the base and quote assets but also the maturity. It’s common to have multiple active futures instruments with different maturities for the same base and quote at the same time and together they form a futures curve, which we will talk more about in a future post. Unlike Uniswap’s market that will live forever, futures market will cease to function after expiry and settlement. Thus, within the ecosystem of SynFutures@v1, new pairs will be constantly created even for the same base and quote assets. At the same time, the logic of derivative market can be quite complicated compared to the spot exchange market and one might not be able to express all the logic inside just one Solidity contract.
Designing SynFutures@v1 architecture
Taking all these into consideration, we use a Factory contract to govern the creation of new market and track all markets similarly to Uniswap. In addition, we adopt the proxy pattern to reduce the gas consumption when creating new markets. Due to the intrinsic complexity of futures market, the logic is split into two Solidity contracts, namely Futures and Amm. User’s fund will go directly into Futures contract, who records and updates users’ account info such as current position, margin balance, social loss etc. when they deposit, withdraw or trade. Amm contract is responsible for maintaining the constant product model-based market, tracking the spot index price, updating on-chain state to maintain proper mark price, and instructing Futures contract to update corresponding user’s account info.

In SynFutures@v1, we use both Uniswap V2 pair and Chainlink aggregator as our spot index price feeders. The Amm contract itself is an abstract contract trying to capture the common logic and leaving specific virtual methods to be overridden. UniswapAmm and ChainlinkAmm derived from the Amm contract in SynFutures@v1 reflects and resolves the differences between the feeders to provide our users a similar trading experience. Thus, when creating a new futures market in SynFutures@v1, one actually creates a pair of proxies, with AmmProxy pointing to either UniswapAmm or ChainlinkAmm and FuturesProxy contract pointing to the Futures contract. As such, creating a new futures market in SynFutures@v1 costs only 0.6~0.7 million gas, compared with 2.7 million gas for a new Uniswap V2 pair.
On-chain oracle and assets status quo
Ideally, we would love to enable our users to create futures for any base and quote assets. However, futures market requires stable spot price oracles for the settlement price at expiry and currently the on-chain world doesn’t have enough such price feeders. In SynFutures@v1, we use Chainlink and Uniswap V2 pair as our spot index price feeder, with caution. We will put up a tutorial showing how you can issue an ERC20 asset, create spot market with Uniswap V2 and then create futures market with SynFutures@v1.
Different feeders have different characteristics. To provide a consistent trading experience for our users, we need to capture all the differences and hide them behind the scenes. We have already talked about the reflections on the Amm side earlier. To fulfill the target, we also need to wrap the external price feeders with UniswapOracle and ChainlinkOracle and adapt the queried price into proper format. Note that, different futures markets with the same base and quote but different maturity can safely share the same UniswapOracle or ChainlinkOracle. Thus, there is no need resorting to the proxy pattern here. Just like there is a Factory contract govern the creating of new futures market, we introduce OracleController contract to govern the creating of new oracle and track all available oracles in SynFutures@v1.
Maintaining on-chain mark price state
Drawing from traditional and centralized market practices, SynFutures@v1 divides the life cycle of a futures market into three stages: TRADING, SETTLING, and SETTLED , where SETTLING state is introduced to minimize last minute price manipulation by prohibiting users to open or increase positions in the final hour of a market.
While user’s trade follows the constant product model, to prevent a brief second-long spike in price resulting in a complete liquidation of traders’ positions, SynFutures@v1 uses mark price to determine whether an account is safe. In the TRADING state, the mark price is defined as the spot index price plus the mark basis. The spot index reflects real-time changes in the spot market, and mark basis uses Exponential Moving Average (EMA) technique to record the difference between futures and spot. In the SETTLING state, the mark price is calculated following the Time Weighted Average Price (TWAP) mode according to spot index price to force the settlement price converges to the price provided by the corresponding oracle.

To cope with the EMA and TWAP mode, both UniswapAmm and ChainlinkAmm need to update the on-chain MarkPriceState periodically and switch to proper state as time passes. To allow user’s activity to drive the update of futures market, contracts of SynFutures@v1 are designed in a way that user’s action won’t easily be reverted by using bool return value to indicate whether or not the transaction is succeeded. Basically, all user’s actions follow the pattern that firstly update the corresponding state and then trying to fulfill user’s action according to the updated state. In the figure above, we highlight all the actions that are allowed in each state and all the actions that follow the update-then-execute pattern.
Wrapping up
Reducing gas consumption for the presented architecture is not an easy job. We have applied different techniques , such as reducing the number of cross contract calls, saving slot consumption by carefully packing multiple on-chain state into one single slot and computing e^{-x} in a gas efficient way, among others. It was fun and we shall illustrate each of the technic in a later stage. The results were comforting too. Gas consumption of a trade transaction in SynFutures@v1 has been reduced to around 0.2 million gas, a big improvement compared to other on-chain derivative markets as of today.
We managed to finish the whole system with around 2500 lines of solidity codes and the code itself received good feedback from PeckShield as they wrote in the audit report: “The system presents a clean and consistent design that makes it a distinctive and valuable addition of innovation to current DeFi ecosystem. The current code base is well structured and neatly organized”. Still there are lots of problems waiting to be solved regarding to building proper on-chain derivative markets and we will share with you all our findings along the way. Stay tuned!
💬 Join our community!
We have launched SynFutures@v1 testnet! We ardently look forward to your participation and feedback.
Please visit our website at www.synfutures.com or join our discussion on Medium /Twitter/Reddit/Discord.