Perps V3
Perps v3 is designed for onchain perpetual futures trading of a wide range of assets, on optimistic EVM rollups.
Traders can take the following actions:
Create an account
Manage margin balances
Commit orders
Delegate access
Keepers can take the following actions:
Settle orders committed by traders
Liquidate accounts
Features
Perps V3.1
Cross margin: account margin can be used across multiple positions on markets
Only async (delayed offchain) orders: async orders seems to be the way forward in general
No order cancellation: Removed one extra action for keepers to perform and LPs to pay for
Role Based Access Control for modifying collateral, opening/closing positions - for full extensibility and composability
Utilization interest rate
Single position per market , and single pending order
Perps v3.2
Multi collateral: accepts any synths configured in the system as margin for an account
What are the major differences between Perps V2 and V3?
Perps Accounts - Before interacting with the markets traders first create an account, represented as an NFT. An account on Optimism can own many perps accounts, which allows for isolating collateral and opening many positions on a market. Each interaction will take this
accountId
as a parameter.Cross margin - All positions in a perps account are cross-margined against the provided collateral. If the account's collateral drops below their maintenance margin, all positions will be closed and all collateral in the account will be liquidated.
Alternate collateral - Perps accounts can now contain more collateral types than sUSD. These collaterals will increase your available margin based on the latest oracle price. If the total USD value of these collaterals drops below your maintenance margin, all collateral types will be liquidated.
Start here
Trading SDK
To better understand how to trade perps, see Perps Python SDK
End to End Tests
To best understand the process of building a perp trading integration, see the below tests:
Requirements
Perps v3 configured to use oracle contracts which comply with ERC-7412. Use the client library when building off-chain integrations like UIs and bots.
Get started
Call the
getMarkets
function to retrieve the list ofmarketIds
the list of available markets.Additional market info call be retrieved by calling
getMarketSummary
with those market ids and reviewing theMarketCreated
events.Fetch other market settings using the
marketId
using functions likegetFundingParameters
andgetLiquidationParameters
Account Creation
Call
PerpsMarketProxy.createAccount()
to create an account with a randomaccountId
You can also specify an
accountId
, which will revert if the account already exists
Re-using the
AccountModule
from v3 core system which comes packaged with RBAC.The account owner can delegate
PERPS_MODIFY_COLLATERAL
role to another address using:
Deposit Margin
For Base see Base Andromedato handle USDC
Approve spending margin
Deposit margin with ModifyCollateral
Managing Margin Balances
For Base see Base Andromedato handle USDC
Each perps account holds assets to use as margin for their positions. Fetch margin balances using these functions on the PerpsMarketProxy
contract:
totalCollateralValue(accountId)
: Get the USD value of all collateral in the accountgetAvailableMargin(accountId)
: Get the USD value of the margin available to use as collateral for future positionsgetWithdrawableMargin(accountId)
: Get the USD value of the margin you can withdraw immediatelygetRequiredMargins(accountId)
: Get USD values of the margin requirements for the specified account, given their open positions
Commit Order
See a sample order commitment transaction here.
Given an account with some available margin, a trader can commit orders to a perps market. That order will be settled by a keeper according to the specified settlementStrategyId
. The Andromeda deployment uses Pyth oracles to settle your order at a future price after a short delay.
Orders are handled asynchronously. Traders submit a
commitOrder
transaction, which creates an order to be settled by a keeper.The
commitOrder
function takes a struct containing all of the order information as an argument. You can see an example order commitment here including the arguments to create this struct.Use
0
assynthMarketId
for snxUSD.Use any other synth that has a
maxCollateralAmount
set by owner of factory to add to account’s margin.By providing a negative
amountDelta
, you are able to withdraw collateral of your choosing.Note: there are checks in place to ensure you cannot remove more than the required maintenance margin.
Call PerpsMarketProxy.commitOrder(commitment) to commit an order. The input commitment is a tuple configuring the order. Here are some recommendations for those inputs:
marketId
: CallgetMarkets()
andmetadata
to get more info about the marketsaccountId
: TheaccountId
that has available marginsizeDelta
: A wei value of the size in units of the asset being tradedsettlementStrategyId
: Recommended0
for Pyth settlement. CallgetSettlementStrategy
for more detailsacceptablePrice
: Minimum fill price for longs, maximum fill price for shortstrackingCode
: A bytes32 encoded value for tracking integrator volumereferrer
: An address for configured integrators to receive a share of fees.
sizeDelta
is the change in size of the position. Can determine long/short based on this value.A settlement strategy is required in order to commit orders. Here’s an example of one that uses a pyth offchain settlement strategy:
Order Settlement
See a sample order settlement transaction here.
Orders will typically be settled by a keeper (which you can run - see Perps V3 Keepers) who fetches the price data from Pyth and fills orders for a fee. You can check getOrder(accountId)
for a given account to view the status of the order. The sizeDelta
will be set to 0 when the order is filled, otherwise it will expire and can be replaced with another order.
Events emitted to track orders:
Orders emit
OrderCommitted
andOrderSettled
events to track these interactions.For a sample
OrderCommitted
event, review this transaction.For a sample
OrderSettled
event, review this transaction.See this repo for a subgraph implementation
Order status
Is there a method to build a trade preview including fees, fill price, and liquidation prices?
There is no single method for quotes, however there are individual methods for these values.
computeOrderFees
will return the fees and estimated fill price for a given order size.Liquidation prices are not available directly. Since positions are cross-margined individual position liquidation prices will change depending on the market. Instead, you can fetch the margin requirements using
getRequiredMargins
Positions are liquidated when an account's
availableMargin
is below therequiredMaintenanceMargin
How can I tell if an account has an open order?
Fetch orders using the
getOrder(marketId, accountId)
function.If the
sizeDelta
value is 0 there is no open order. When an order is filled, this value is set to 0.Other values may be returned when there is not an open order. These values are not reset to reduce gas used during order settlement.
How can I tell if an account has an open position?
Fetch position using the
getOpenPosition(marketId, accountId)
function.The return will include the position size as well as any funding and pnl accrued since the position was opened.
Settlement Keepers
Keepers settle orders after the
settlementTime
has been reached. You can get this time from theOrderCommitted
event or by callinggetOrder
for an account.The
settle
function reverts with information for retrieving the offchain price data (url
anddata
)The
settlePythOrder
function take this price data as well as an argument with encodedaccountId
andmarketId
parameters. Review this transaction to see sample inputs.
If the order is valid and within settlement window, this function will settle the order and update its accounting of the new position.
More info at Perps V3 Keepers
Liquidation Keepers
Call either:
If the account is already flagged for liquidation, the call will proceed with liquidating as much of the account’s position as possible.
If the account is not, it will check if the account is eligible and proceed to liquidate.
Otherwise, the call reverts.
Iterates through all accounts flagged for liquidation and attempts to liquidate.
Gas could be high but so are the rewards 💰
Other Notes
Liquidation Margins
An account is subject to margin requirements as determined by the following values configurable for each market:
When opening a position on a given market, the initial margin requirement is a fraction of the notional value. The fraction is determined by calculating the size’s impact on the skew (position size / skewScale), multiplied by the initialMarginFraction
plus the minimumInitialMarginScalar
.
Once a positive is live, the liquidation threshold is determined by the maintenceMargin
which is the initialMargin requirement multiplied by the configured maintenceMarginScalar
.
To determine if an account is liquidatable, the account’s availableMargin
must be greater than all calculated maintenance margins combined for each market the account has a position open. The maintenance margin also includes the liquidation settlement reward configured per market as a % of the notional size being liquidated.
availableMargin
is determined by subtracting any unrealized pnl to the available collateral margin.
Available functions that will come in handy:
Estimate Order Validity
There are some functions you can call initially to determine if an order will go through:
Max Liquidatable Amount
Each market has parameters that dictate how much can be liquidated at any given point.
The equation for max liquidation per second is as follows:
Note: the multiplier is an additional way to limit max liquidation amount per market.
Based on the configured window, maxSecondsInLiquidationWindow
, and maxLiquidationAmountPerSecond
, the max liquidatable amount in any given window is:
maxSecondsInLiquidationWindow * maxLiquidationAmountPerSecond
Example:
In this scenario, a max of 500 ETH
can be liquidated in a 5 second window.
Below functions are permissioned to Synthetix governance
Factory Owner
Each proxy is considered to be one “supermarket”, and is initialized with the factory owner as the owner of this supermarket. The supermarket consists of a set of markets that it controls for which cross margin is applied. Each account that’s created is scoped to the supermarket and cannot be used on other supermarkets.
Supermarkets can only be initialized once which registers them with the Core system using the following call (returns the registered market id with core system):
Owner can set other global parameters that apply to all markets:
synthetix-v3/GlobalPerpsMarketConfiguration.sol at main · Synthetixio/synthetix-v3
Create perps market:
Two markets have been created on OP Goerli so far:
100
: ETH market200
: BTC market
Set configuration parameters
If you need the configuration of any of the above created markets, here are the functions you can call:
synthetix-v3/PerpsMarketConfiguration.sol at main · Synthetixio/synthetix-v3
Add settlement strategy for async orders
You can always query getSettlementStrategy
to get the details.
Last updated