OmniTrade Technical Overview

Software Architecture

The main components of the platform are:

  1. Vault

  2. Routers

  3. Price Feeds

  4. Charm

  5. OLP

Vault

The Vault contract stores deposits and handles the main trading functions.

  • Deposits: Funds are deposited into the Vault through the minting of OLP tokens. e.g. if the price of OLP is $1.50, a user can mint 1 OLP by depositing 1.50 USDC tokens.

  • Withdrawals: Funds can be withdrawn from the vault through the burning of OLP tokens. e.g. if the price of OLP is $1.50, a user can burn 1 OLP to redeem 1.50 USDC tokens.

  • Swaps: The vault allows swapping of the tokens held in the vault. e.g. if the price of ETH is $5000 a user can swap 1 ETH for 5000 USDC through the swap function of the vault.

  • Liquidations: A position can be liquidated by keepers if the losses of the position reduces the collateral to the point where position size / remaining collateral is more than the max allowed leverage.

Router

The Router contracts provide convenience functions on top of the vault. e.g. the vault requires tokens to be sent to it then the swap function called to execute the swap, the router handles transferring the tokens to the vault as well as wrapping / unwrapping of native tokens if required.

The PositionRouter contract handles a two part transaction process for increasing or decreasing long / short positions, this process helps to reduce front-running issues:

  1. A user sends the request to increase / decrease a position to the PositionRouter

  2. A keeper requests the index price from an aggregate of exchanges

  3. The keeper then executes the position at the current index price

  4. If the position cannot be executed within the allowed slippage the request is cancelled and the funds are sent back to the user

A user can execute the position on their own if three minutes have passed between the request transaction and the execution transaction. The function of the position keepers is to provide convenience and the protocol can continue to operate even without these keepers.

Price Feeds

The PriceFeed contract accepts submissions from the price feed keeper. This keeper calculates prices using the median price of Binance, Bitfinex and Coinbase. There are two types of keepers:

  • Price feed keeper: submits prices routinely for swaps

  • Position keeper: submits prices when executing a position

The vault uses the price from the keeper if it is within a configured percentage of the corresponding DIA price. If the price exceeds this threshold then a spread would be created between the bounded price and the DIA price, this threshold is based on the historical max deviation of the DIA price from the median price of reference exchanges. For example, if the max deviation is 2.5% and the price of the token on DIA is $100, if the keeper price is $103, then the pricing on the vault would be $100 to $103. When opening a long position, the higher price is used and when closing the lower price is used, for short positions, the lower price is used when opening and the higher price is used for closing.

Prices from the keeper also have an expiry of five minutes, if the last price has been submitted more than five minutes ago, the DIA price will be used instead.

For liquidations, these can only occur if the DIA price reaches the liquidation price for a position.

Aside from the keeper nodes, watcher nodes are also used to verify that the prices submitted by the keepers have not been tampered with. Watcher nodes continually compute the median price and compare this with the prices submitted by keepers, if the prices submitted by a keeper does not match the computed median price, then the watcher sends a transaction to enforce a spread between the keeper price and the DIA price. For example, if the keeper is operating normally and the DIA price is $100 while the keeper price is $101, there would be no spread and $101 would be used for pricing, if the keeper is not operating normally, and the watcher sends a transaction to enforce a spread, then the pricing used would be $100 to $101.

On each fast price update, contract variables store the percentage change in price for the update as well as the percentage change of the DIA price since the last update, if the cumulative percentage change in the fast prices over a duration exceeds the cumulative percentage change in the DIA prices by a configured threshold, the spread between the fast price and DIA price will be automatically enabled. The configuration for this is in Vault.priceFeed.secondaryPriceFeed.maxCumulativeDeltaDiffs.

As the price feed contract may be updated to improve its security, the most reliable way to find the contract address for it would be to check the value of Vault.priceFeed.

Access Control

Parameters that can be adjusted by a controller account currently controlled by the contributors:

  • Setting of swap and margin trading fees up to a maximum of 5%

  • Setting of token weights for the OLP pool, token weights affect the dynamic fees of swaps, these fees are such that a swap which increases the balance towards the specified token weight will be lower, while a swap that moves the token weight away from the desired amounts will have higher fees, the details of the calculation can be found from Vault.vaultUtils.getSwapFeeBasisPoints

  • Pausing of swaps or leverage trading for emergency use

  • Setting of the maximum allowed leverage

  • Setting of maximum total capacity for long and short positions

Parameters that can be adjusted by a timelock controlled by contributors:

  • Listing of new tokens

  • Updating Vault.priceFeed

  • Updating Vault.vaultUtils, the VaultUtils contract validates the opening and closing of positions and also specifies how fees are calculated

  • Updating of gov values

The Timelock works by requiring a 24 hour gap between when the full details of an action is signalled on-chain to when the action is executed. An example flow would be:

  • Timelock.signalSetPriceFeed is called, this specifies the Vault address and the address of the new price feed

  • At least 24 hours must pass

  • Timelock.setPriceFeed can be called, this will update the Vault.priceFeed value

24 hours was selected as it helps to be able to respond quickly to any issues that may occur.

The Timelock contract is monitored by contributors and can be monitored by anyone without coding by subscribing to the Timelock.SignalPendingAction event. This is doable using OpenZeppelin Sentinel. The Timelock contracts can be found by checking the gov values of contracts.

Last updated