Terms of Use
By using any API provided by Drift Labs, you agree to the Terms of Use. If you do not agree to the foregoing, then do not use any such API.
Introduction
Drift Protocol is an open-sourced, decentralised exchange built on the Solana blockchain, enabling transparent and non-custodial trading on cryptocurrencies.
There are language bindings in Typescript and Python! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
This API documentation page is open sourced and available here was created with Slate. Feel free to submit questions/comments in Issues or suggest changes as a PR.
Program Addresses
Enviroment | Program ID | User Interface |
---|---|---|
mainnet-beta | dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH | app |
devnet | dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH | app |
Authentication
To access and interact with a blockchain, such as Solana, you need a keypair, which consists of a public key and a private key. The private key should be kept secure and not shared with anyone else.
To generate a new keypair, you can use the Solana Tool Suite by running the following command on the command line:
solana-keygen new --outfile ~/.config/solana/my-keypair.json
This command will create a new keypair and store it in a JSON file located at ~/.config/solana/my-keypair.json.
To allow SDK code to use this keypair for authentication, you need to set the ANCHOR_WALLET environment variable to the path of the JSON file that contains the keypair. You can do this by running the following command:
export ANCHOR_WALLET=~/.config/solana/my-keypair.json
This command sets the ANCHOR_WALLET environment variable to the path of the JSON file that contains your keypair, so that SDK code can access it when needed.
Client
Typescript
Install @drift-labs/sdk from npm using yarn:
yarn add @drift-labs/sdk
auto-generated documentation here: [https://drift-labs.github.io/protocol-v2/sdk/]
Python
Install driftpy from PyPI using pip:
pip install driftpy
auto-generated documentation here: [https://drift-labs.github.io/driftpy/]
Connection
import {Connection} from "@solana/web3.js";
// the default RPC for devnet is `https://api.devnet.solana.com`
const connection = new Connection('https://api.mainnet-beta.solana.com');
from solana.rpc.async_api import AsyncClient
url = 'https://api.mainnet-beta.solana.com' # replace w/ any rpc
connection = AsyncClient(url)
The connection object is used to send transactions to the Solana blockchain. It is used by the DriftClient to send transactions to the blockchain.
Wallet
import {Wallet, loadKeypair} from "@drift-labs/sdk";
const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile));
from solana.keypair import Keypair
from anchorpy import Wallet
import os
import json
key_pair_file = '~/.config/solana/my-keypair.json'
with open(os.path.expanduser(key_pair_file), 'r') as f: secret = json.load(f)
kp = Keypair.from_secret_key(bytes(secret))
wallet = Wallet(kp)
The wallet used to sign solana transactions. The wallet can be created from a private key or from a keypair file.
Make sure this wallet has some SOL first. SOL is used to pay for transactions and is required as rent for account intializations.
Client Initialization
import {Connection} from "@solana/web3.js";
import {Wallet, loadKeypair, DriftClient} from "@drift-labs/sdk";
const connection = new Connection('https://api.mainnet-beta.solana.com');
const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))
const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
driftClient.subscribe();
import driftpy
from anchorpy import Wallet, Provider
from driftpy.constants.config import configs
from driftpy.clearing_house import ClearingHouse
# set connection and wallet
# ...
provider = Provider(connection, wallet)
config = configs['mainnet'] # or devnet
drift_client = ClearingHouse.from_config(config, provider)
Parameter | Description | Optional | Default |
---|---|---|---|
connection | Connection object specifying solana rpc url | No | |
wallet | The wallet used to sign transactions sent to solana blockchain | No | |
programId | Drift program id | Yes | dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH |
env | devnet or mainnet-beta . Used to automatically derive market accounts to subscribe to if they're not explicitly set |
Yes | |
perpMarketIndexes | Which perp markets accounts to subscribe to. | Yes | Derived based on env |
spotMarketIndexes | Which spot markets accounts to subscribe to. | Yes | Derived based on env |
oracleInfos | Which oracles accounts to subscribe to. | Yes | Derived based on env |
accountSubscription | Whether to use websocket or polling to subscribe to on-chain accounts e.g. markets, users, oracle. | Yes | Websockets |
opts | Transaction confirmation status options | Yes | {preflightCommitment: "processed", commitment: "processed"} |
activeSubAccountId | Which sub account to use initially | Yes | 0 |
subAccountIds | All the sub account ids to subscribe to. If this and authoritySubAccountMap are empty, subscribes to all sub account ids. | Yes | [] |
authority | Which user account authority you're signing for. Only set if you're signing for delegated account. | Yes | wallet.publicKey |
authoritySubAccountMap | Map of authority to sub account ids to subscribe to. Only necessary if using multiple delegate accounts. If this and subAccountIds are empty, subscribes to all sub account ids. | Yes | {} |
includeDelegates | Whether or not to subscribe to delegates when subAccountIds and authoritySubAccountMap are empty | Yes | false |
userStats | Whether or not to listen subscribe to user stats account. | Yes | false |
User Initialization
const [txSig, userPublickKey] = await driftClient.initializeUser(
0,
"toly"
);
# todo: cannot init with name
tx_sig = await drift_client.intialize_user(0)
Parameter | Description | Optional | Default |
---|---|---|---|
subAccountId | The sub account id for the new user account. | Yes | 0 |
name | Display name for the user account | Yes | Main Account |
referrerInfo | The address of the referrer and referrer stats accounts | Yes |
Sub account ids are monotonic. The first user account created will have sub account id 0, the second will have sub account id 1, etc.
The next sub account id can be found by calling driftClient.getNextSubAccountId()
.
Updating User
Users accounts can update names, set custom max intial margin ratio, enable margin trading, and add a delegate account.
const subaccountId = 0;
// set max 1x intiial leverage
await this.driftClient.updateUserCustomMarginRatio(
MARGIN_PRECISION,
subaccountId
);
// enable spot margin trading
await this.driftClient.updateUserMarginTradingEnabled(
true,
subaccountId
);
// add a delegate this user account
await this.driftClient.updateUserDelegate(
new PublicKey('satoshi'),
subaccountId
);
Switching Sub Accounts
driftClient.switchActiveUser(
1,
);
Parameter | Description | Optional | Default |
---|---|---|---|
subAccountId | The sub account to switch to | No | 0 |
authority | The authority of the sub account you're signing for. Only needed for delegate accounts | Yes | Current authority |
Deleting User Account
If an account contains no assets or liabilites, a user account can be deleted to reclaim rent.
driftClient.deleteUser(
1,
);
Depositing
const marketIndex = 0; // USDC
const amount = driftClient.convertToSpotPrecision(marketIndex, 100); // $100
const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(marketIndex);
driftClient.deposit(
amount,
marketIndex,
associatedTokenAccount,
);
from driftpy.accounts import get_spot_market_account
from spl.token.instructions import get_associated_token_address
spot_market_index = 0 # USDC
spot_market = await get_spot_market_account(drift_client.program, spot_market_index)
user_token_account = get_associated_token_address(drift_client.authority, spot_market.mint)
amount = 100 * QUOTE_PRECISION # $100
tx_sig = await drift_client.deposit(amount, spot_market_index, user_token_account)
Parameter | Description | Optional | Default |
---|---|---|---|
amount | The amount to deposit in spot market's token mint precision | No | |
marketIndex | The spot market index you're depositing into | No | |
associatedTokenAccount | The public key of the token account you're depositing from. For sol, it can be the wallet's public key | No | |
subAccountId | The sub account you're depositing too | Yes | active sub account |
reduceOnly | Whether the deposit should only reduce borrow | Yes | false |
Withdrawing
const marketIndex = 0;
const amount = driftClient.convertToSpotPrecision(marketIndex, 100);
const associatedTokenAccount = await driftClient.getAssociatedTokenAccount(marketIndex);
driftClient.withdraw(
amount,
marketIndex,
associatedTokenAccount,
);
Parameter | Description | Optional | Default |
---|---|---|---|
amount | The amount to withdraw in spot market's token mint precision | No | |
marketIndex | The spot market index you're withdrawing from | No | |
associatedTokenAccount | The public key of the token account you're withdrawing to. For sol, it can be the wallet's public key | No | |
reduceOnly | Whether the withdraw should only decrease a deposit and block a new borrow | Yes | false |
Withdrawing can lead to a borrow if the user has no deposits in the market and the user has enough margin to cover it.
Transferring Deposits
const marketIndex = 0;
const amount = driftClient.convertToSpotPrecision(marketIndex, 100);
const fromSubAccountId = 0;
const toSubAccountId = 1;
driftClient.transferDeposit(
amount,
marketIndex,
fromSubAccountId,
toSubAccountId,
);
Parameter | Description | Optional | Default |
---|---|---|---|
amount | The amount to transfer in spot market's token mint precision | No | |
marketIndex | The spot market index you're transferring deposits in | No | |
fromSubAccountId | The sub account you're withdrawing from | No | |
toSubAccountId | The sub account you're depositing too | No |
Order Types
MARKET, LIMIT, ORACLE orders all support auction parameters.
Type | Description |
---|---|
MARKET | Market order. |
LIMIT | Limit order. |
TRIGGER_MARKET | Stop / Take-profit market order. |
TRIGGER_LIMIT | Stop / Take-profit limit order. |
ORACLE | Market order using oracle offset for auction parameters. |
Placing Perp Order
// market buy for 100 SOL-PERP @ $21.20->$21.30 over 60 slots (~30 seconds)
// after 60 slots, market buy 100 SOL-PERP @ $21.35 until maxTs
const orderParams = {
orderType: OrderType.MARKET,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
auctionStartPrice: driftClient.convertToPricePrecision(21.20),
auctionEndPrice: driftClient.convertToPricePrecision(21.30),
price: driftClient.convertToPricePrecision(21.35),
auctionDuration: 60,
maxTs: now + 100,
}
await driftClient.placePerpOrder(orderParams);
// bid for 100 SOL-PERP @ $21.23
const orderParams = {
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
price: driftClient.convertToPricePrecision(21.23),
}
await driftClient.placePerpOrder(orderParams);
// ask for 100 SOL-PERP @ ${OraclePrice} + .05
const orderParams = {
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.SHORT,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
oraclePriceOffset: driftClient.convertToPricePrecision(.05).toNumber(),
}
await driftClient.placePerpOrder(orderParams);
from driftpy.types import *
from driftpy.constants.numeric_constants import BASE_PRECISION, PRICE_PRECISION
subaccount_id = 0
market_index = 0
# place order to long 1 SOL-PERP @ $21.88 (post only)
bid_params = OrderParams(
order_type=OrderType.LIMIT(),
market_type=MarketType.PERP(),
direction=PositionDirection.LONG(),
user_order_id=0,
base_asset_amount=int(1 * BASE_PRECISION),
price=21.88 * PRICE_PRECISION,
market_index=market_index,
reduce_only=False,
post_only=PostOnlyParams.TRY_POST_ONLY(),
immediate_or_cancel=False,
trigger_price=0,
trigger_condition=OrderTriggerCondition.ABOVE(),
oracle_price_offset=0,
auction_duration=None,
max_ts=None,
auction_start_price=None,
auction_end_price=None,
)
await drift_client.get_place_perp_order(bid_order_params, subaccount_id)
Parameter | Description | Optional | Default |
---|---|---|---|
orderType | The type of order e.g. market, limit | No | |
marketIndex | The market to place order in | No | |
direction | The direction of order e.g. long (bid) or short (ask) | No | |
baseAssetAmount | The amount of base asset to buy or sell | No | |
marketType | The type of market order is for e.g. PERP or SPOT | Yes | PERP |
price | The limit price for order | Yes | 0 |
userOrderId | Unique order id specified by user | Yes | 0 |
reduceOnly | If the order can only reduce positions | Yes | false |
postOnly | If the order can only be a maker | Yes | false |
triggerPrice | at what price order is triggered. only applicable for triggerMarket and triggerLimit orders | Yes | |
triggerCondition | whether order is triggered above or below triggerPrice. only applicable for triggerMarket and triggerLimit orders | Yes | |
oraclePriceOffset | priceOffset for oracle derived limit price. only applicable for limit and oracle orders | Yes | |
auctionDuration | how many slots the auction lasts. only applicable for market and oracle orders | Yes | |
auctionStartPrice | the price the auction starts at | Yes | |
auctionEndPrice | the price the auction ends at | Yes | |
maxTs | the max timestamp (on-chain unix timestamp) before the order expires | Yes |
Placing Spot Order
const orderParams = {
orderType: OrderType.LIMIT,
marketIndex: 1,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToSpotPrecision(1, 100),
price: driftClient.convertToPricePrecision(100),
}
await driftClient.placeSpotOrder(orderParams);
Parameter | Description | Optional | Default |
---|---|---|---|
orderType | The type of order e.g. market, limit | No | |
marketIndex | The market to place order in | No | |
direction | The direction of order e.g. long (bid) or short (ask) | No | |
baseAssetAmount | The amount of base asset to buy or sell | No | |
marketType | The type of market order is for e.g. PERP or SPOT | Yes | SPOT |
price | The limit price for order | Yes | 0 |
userOrderId | Unique order id specified by user | Yes | 0 |
reduceOnly | If the order can only reduce positions | Yes | false |
postOnly | If the order can only be a maker | Yes | false |
triggerPrice | at what price order is triggered. only applicable for triggerMarket and triggerLimit orders | Yes | |
triggerCondition | whether order is triggered above or below triggerPrice. only applicable for triggerMarket and triggerLimit orders | Yes | |
oraclePriceOffset | priceOffset for oracle derived limit price. only applicable for limit and oracle orders | Yes | |
auctionDuration | how many slots the auction lasts. only applicable for market and oracle orders | Yes | |
auctionStartPrice | the price the auction starts at | Yes | |
auctionEndPrice | the price the auction ends at | Yes | |
maxTs | the max timestamp before the order expires | Yes |
Place Orders
const placeOrderParams = [
{
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
price: driftClient.convertToPricePrecision(21.23),
},
{
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.SHORT,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
oraclePriceOffset: driftClient.convertToPricePrecision(.05).toNumber(),
}
];
await driftClient.placeOrders(placeOrderParams);
Parameter | Description | Optional | Default |
---|---|---|---|
placeOrderParams | Parameters for place order instructions |
Placing multiple orders in one tx can be cheaper than placing them in separate tx.
Canceling Order
const orderId = 1;
await driftClient.cancelOrder(orderId);
Parameter | Description | Optional | Default |
---|---|---|---|
orderId | The order being canceled | No |
Canceling Order By User Order Id
const userOrderId = 1;
await driftClient.cancelOrderByUserOrderId(userOrderId);
Parameter | Description | Optional | Default |
---|---|---|---|
userOrderId | Unique order id specified by user when order was placed | No |
Cancel Orders
const marketType = MarketType.PERP;
const marketIndex = 0;
const direction = PositionDirection.LONG;
await driftClient.cancelOrders(marketType, marketIndex, direction);
subaccount_id = 0
await drift_client.cancel_orders(subaccount_id) # cancels all orders
Parameter | Description | Optional | Default |
---|---|---|---|
marketType | The market type of orders to cancel. Must be set if marketIndex set | Yes | |
marketIndex | The market index of orders to cancel. Must be set if marketType set | Yes | |
direction | The direction of orders to cancel. | Yes |
To cancel all orders, do not set any parameters.
Cancel and Place Orders
const cancelOrderParams = {
marketType: MarketType.PERP,
marketIndex: 0,
};
const placeOrderParams = [
{
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
price: driftClient.convertToPricePrecision(21.23),
},
{
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.SHORT,
baseAssetAmount: driftClient.convertToPerpPrecision(100),
oraclePriceOffset: driftClient.convertToPricePrecision(.05).toNumber(),
}
];
await driftClient.cancelAndPlaceOrders(cancelOrderParams, placeOrderParams);
Parameter | Description | Optional | Default |
---|---|---|---|
cancelOrderParams | Parameters for cancel orders instruction | ||
placeOrderParams | Parameters for place order instructions |
To cancel all orders, do not set any parameters.
Modifying Order
const updateParams = {
orderId: 1,
newBaseAssetAmount: driftClient.convertToPerpPrecision(200),
}
await driftClient.modifyOrder(orderParams);
Parameter | Description | Optional | Default |
---|---|---|---|
orderId | The order id of order to modify | No | |
newBaseAssetAmount | The amount of base asset to buy or sell | Yes | |
newDirection | The direction of order e.g. long (bid) or short (ask) | Yes | |
newLimitPrice | The limit price for order | Yes | |
reduceOnly | If the order can only reduce positions | Yes | |
postOnly | If the order can only be a maker | Yes | |
newTriggerPrice | at what price order is triggered. only applicable for triggerMarket and triggerLimit orders | Yes | |
newTriggerCondition | whether order is triggered above or below triggerPrice. only applicable for triggerMarket and triggerLimit orders | Yes | |
newOraclePriceOffset | priceOffset for oracle derived limit price. only applicable for limit and oracle orders | Yes | |
auctionDuration | how many slots the auction lasts. only applicable for market and oracle orders | Yes | |
auctionStartPrice | the price the auction starts at | Yes | |
auctionEndPrice | the price the auction ends at | Yes | |
maxTs | the max timestampe before the order expires | Yes |
Modify order cancels and places a new order.
Modifying Order By User Order Id
const updateParams = {
userOrderId: 1,
newBaseAssetAmount: driftClient.convertToPerpPrecision(200),
}
await driftClient.modifyOrder(orderParams);
Parameter | Description | Optional | Default |
---|---|---|---|
userOrderId | The user order id of order to modify | No | |
newBaseAssetAmount | The amount of base asset to buy or sell | Yes | |
newDirection | The direction of order e.g. long (bid) or short (ask) | Yes | |
newLimitPrice | The limit price for order | Yes | |
reduceOnly | If the order can only reduce positions | Yes | |
postOnly | If the order can only be a maker | Yes | |
newTriggerPrice | at what price order is triggered. only applicable for triggerMarket and triggerLimit orders | Yes | |
newTriggerCondition | whether order is triggered above or below triggerPrice. only applicable for triggerMarket and triggerLimit orders | Yes | |
newOraclePriceOffset | priceOffset for oracle derived limit price. only applicable for limit and oracle orders | Yes | |
auctionDuration | how many slots the auction lasts. only applicable for market and oracle orders | Yes | |
auctionStartPrice | the price the auction starts at | Yes | |
auctionEndPrice | the price the auction ends at | Yes | |
maxTs | the max timestampe before the order expires | Yes |
Modify order cancels and places a new order.
Settle Perp PNL
const marketIndex = 0;
const user = driftClient.getUser();
await driftClient.settlePNL(
user.userAccountPublicKey,
user.getUserAccount(),
marketIndex
);
Parameter | Description | Optional | Default |
---|---|---|---|
settleeUserAccountPublicKey | User address you're settling pnl for | No | |
settleeUserAccount | User account data you're settling pnl for | No | |
marketIndex | Market index for the perp market | No |
Get Spot Market Account
const marketIndex = 1;
const spotMarketAccount = driftClient.getSpotMarketAccount(marketIndex);
Parameter | Description | Optional | Default |
---|---|---|---|
marketIndex | The market index for the spot market | No |
Get Perp Market Account
const marketIndex = 0;
const perpMarketAccount = driftClient.getPerpMarketAccount(marketIndex);
Parameter | Description | Optional | Default |
---|---|---|---|
marketIndex | The market index for the perp market | No |
User
Get User
const user = await driftClient.getUser();
Parameter | Description | Optional | Default |
---|---|---|---|
subAccountId | The sub account id of user to get | Yes | active sub account |
authority | The authority of user to get. Only necessary if using multiple delegate accounts | Yes | current authority |
Getting Deposit/Borrow Amounts
const marketIndex = 0;
const tokenAmount = user.getTokenAmount(
marketIndex,
);
const isDeposit = tokenAmount.gte(new BN(0));
const isBorrow = tokenAmount.lt(new BN(0));
Parameter | Description | Optional | Default |
---|---|---|---|
marketIndex | Market index for the spot market | No |
If token amount is greater than 0, it is a deposit. If less than zero, it is a borrow.
Get Perp Position
const marketIndex = 0;
const baseAssetAmount = user.getPerpPosiiton(
marketIndex,
)?.baseAssetAmount;
const isLong = baseAssetAmount.gte(new BN(0));
const isShort = baseAssetAmount.lt(new BN(0));
Parameter | Description | Optional | Default |
---|---|---|---|
marketIndex | Market index for the perp market | No |
If base amount is greater than 0, it is a long. If less than zero, it is a short.
Get Order
const orderId = 1;
const order = user.getOrder(
orderId,
);
Parameter | Description | Optional | Default |
---|---|---|---|
orderId | Order id for the order you're getting | No |
Get Order By User Order Id
const userOrderId = 1;
const order = user.getOrderByUserOrderId(
userOrderId,
);
Parameter | Description | Optional | Default |
---|---|---|---|
userOrderId | User order id for the order you're getting | No |
Get Open Orders
const order = user.getOpenOrders();
Get Unrealized Perp Pnl
const pnl = await user.getUnrealizedPNL();
Parameter | Description | Optional | Default |
---|---|---|---|
withFunding | Whether to included unsettled funding payments | Yes | false |
marketIndex | Whether to only return pnl for specific market | Yes |
Get Unrealized Funding Pnl
const pnl = await user.getUnrealizedFundingPNL();
Parameter | Description | Optional | Default |
---|---|---|---|
marketIndex | Whether to only return pnl for specific market | Yes |
Get Total Collateral
const totalCollateral = await user.getTotalCollateral();
Parameter | Description | Optional | Default |
---|---|---|---|
marginCategory | Initial or Maintenance | Yes | Initial |
Asset weights vary based on whether you're checking the initial or maintenance margin requirement. Initial is used for initial leverage extension, maintenance for determining liquidations.
Get Margin Requirement
const marginRequirement = await user.getMarginRequirement();
Parameter | Description | Optional | Default |
---|---|---|---|
marginCategory | Initial or Maintenance | Yes | Initial |
Liability weights (for borrows) and margin ratios (for perp positions) vary based on whether you're checking the initial or maintenance margin requirement. Initial is used for initial leverage extension, maintenance for determining liquidations.
Get Free Collateral
const freeCollateral = await user.getFreeCollateral();
Free collateral is the difference between your total collateral and your initial margin requirement.
Get Leverage
const leverage = await user.getLeverage();
Leverage is the total liability value (borrows plus total perp position) divided by net asset value (total assets plus total liabilities)
Orderbook
Slot Subscription
import {Connection} from "@solana/web3.js";
import {SlotSubscriber} from "@drift-labs/sdk";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const slotSubscriber = new SlotSubscriber(connection);
await slotSubscriber.subscribe();
const slot = slotSubscriber.getSlot();
slotSubscriber.eventEmitter.on('newSlot', async (slot) => {
console.log('new slot', slot);
});
Parameter | Description | Optional | Default |
---|---|---|---|
connection | Connection object specifying solana rpc url | No |
The slot subscriber subscribes to the latest slot and updates the slot value every time a new slot is received. The state of the orderbook is dependent on the slot value, so to build the orderbook you must keep track of the slot value.
User Subscription
import {Connection} from "@solana/web3.js";
import {DriftClient, UserMap, Wallet, loadKeypair} from "@drift-labs/sdk";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))
const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
await driftClient.subscribe();
const includeIdleUsers = false;
const userMap = new UserMap(driftClient, {type: 'websocket'}, false);
await userMap.subscribe();
Parameter | Description | Optional | Default |
---|---|---|---|
driftClient | DriftClient object | No | |
accountSubscription | Whether to use websocket or polling to subscribe to users | No | |
includeIdle | Whether to include idle users. An idle user has had no orders, perp position or borrow for 7 days | Yes |
Orders are stored on user accounts. To reconstruct the orderbook, you must keep track of the user accounts that have orders. The user map subscribes to user account updates.
Orderbook Subscription
import {DLOBSubscriber} from "@drift-labs/sdk";
// on-chain subscription to users
const userMap = new UserMap(driftClient, {type: 'websocket'}, false);
await userMap.subscribe();
const dlobSubscriber = new DLOBSubscriber({
driftClient,
dlobSource: userMap,
slotSource: slotSubscriber,
updateFrequency: 1000,
});
await dlobSubscriber.subscribe();
import {DLOBApiClient, DLOBSubscriber} from "@drift-labs/sdk";
// Polling from api
const dlobApiClient = new DLOBApiClient({
url: 'https://dlob.drift.trade/orders/idlWithSlot',
});
const dlobSubscriber = new DLOBSubscriber({
driftClient,
dlobSource: dlobApiClient,
slotSource: slotSubscriber,
updateFrequency: 1000,
});
await dlobSubscriber.subscribe();
Parameter | Description | Optional | Default |
---|---|---|---|
driftClient | DriftClient object | No | |
dlobSource | Where to build the orderbook from. Can subscribe to user accounts on-chain using UserMap or request DLOB from api using DLOBApiClient | No | |
slotSource | Where to get slot from | No | |
updateFrequency | How often to rebuild the orderbook from the dlobSource in milliseconds | No |
Get L2 Orderbook
const l2 = dlobSubscriber.getL2({
marketName: 'SOL-PERP',
depth: 50,
});
Parameter | Description | Optional | Default |
---|---|---|---|
marketName | The market name of the orderbook to get. If not set, marketIndex and marketType must be set | Yes | |
marketIndex | The market index of the orderbook to get. If not set, marketName must be set | Yes | |
marketType | The market type of the orderbook to get. If not set, marketName must be set | Yes | |
depth | The depth of the orderbook to get | Yes | 10 |
includeVamm | Whether to include vAMM | Yes | false |
fallbackL2Generators | L2OrderbookGenerators for fallback liquidity e.g. vAmm, openbook, phoenix. Unnecessary if includeVamm is true | Yes |
The L2 orderbook is an aggregate of drift dlob orders and, optionally, fallback liquidity.
Get L3 Orderbook
const l3 = dlobSubscriber.getL3({
marketName: 'SOL-PERP',
});
Parameter | Description | Optional | Default |
---|---|---|---|
marketName | The market name of the orderbook to get. If not set, marketIndex and marketType must be set | Yes | |
marketIndex | The market index of the orderbook to get. If not set, marketName must be set | Yes | |
marketType | The market type of the orderbook to get. If not set, marketName must be set | Yes |
The L3 orderbook contains every maker order on drift dlob, including the address for the user that placed the order.
Events
Event Subscription
import {Connection} from "@solana/web3.js";
import {Wallet, loadKeypair, DriftClient, EventSubscriber} from "@drift-labs/sdk";
const connection = new Connection('https://api.mainnet-beta.solana.com');
const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))
const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
const options = {
eventTypes: [
'DepositRecord',
'FundingPaymentRecord',
'LiquidationRecord',
'OrderRecord',
'OrderActionRecord',
'FundingRateRecord',
'NewUserRecord',
'SettlePnlRecord',
'LPRecord',
'InsuranceFundRecord',
'SpotInterestRecord',
'InsuranceFundStakeRecord',
'CurveRecord',
],
maxTx: 4096,
maxEventsPerType: 4096,
orderBy: 'blockchain',
orderDir: 'asc',
commitment: 'confirmed',
logProviderConfig: {
type: 'websocket',
},
}
const eventSubscriber = new EventSubscriber(connection, driftClient.program, options);
await eventSubscriber.subscribe();
eventSubscriber.eventEmitter.on('newEvent', (event) => {
console.log(event);
});
Parameter | Description | Optional | Default |
---|---|---|---|
connection | Connection object specifying solana rpc url | No | |
program | Anchor program object used to deserialize events from transaction logs | No | |
options.eventTypes | Which events types to trigger event callbacks for | Yes | All events |
options.maxTx | Max number of transactions to keep in memory | Yes | 4096 |
options.maxEventsPerType | Max number of events per event type to keep in memory | Yes | 4096 |
options.orderBy | Whether to sort the tx in memory by the order they occurred on chain ('blockchain') or received by client ('client') | Yes | 'blockchain' |
options.orderDir | Whether to sort the tx in memory to be most recent ('desc') or oldest ('asc') | Yes | 'asc' |
options.commitment | What transaction commitment to wait for | Yes | 'confirmed' |
options.logProviderConfig | Whether to use websocket or polling to listen for tx logs | Yes | {type: "websocket"} |
options.address | Which address to listen to events for. Defaults to drift program. | Yes | dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH |
Protocol events are recorded in transactions logs. To listen for events, one must subscribe to the drift program's transaction logs.
Event Types
Event Type | Description |
---|---|
DepositRecord | A record of a user depositing or withdrawing funds from protocol |
FundingPaymentRecord | A record of a user paying/receiving funding payments |
LiquidationRecord | A record of a user being liquidated |
OrderRecord | A record of a user placing an order, including all of its parameters |
OrderActionRecord | A record of a user action on an order, including place, cancel and fill |
FundingRateRecord | A record of the funding rate changing |
NewUserRecord | A record of a new user |
SettlePnlRecord | A record of a user settling their pnl |
LPRecord | A record of a user adding or removing passive perp liquidity |
InsuranceFundRecord | A record of the insurance fund changing |
SpotInterestRecord | A record of the spot interest changing |
InsuranceFundStakeRecord | A record of a user staking or unstaking from the insurance fund |
CurveRecord | A record of the amm curve updating |
Listening to Perp Market Fills
const marketIndex = 0;
const isPerpMarketFill = (event) => {
if (event.eventType !== 'OrderActionRecord') {
return false;
}
if (event.marketIndex !== marketIndex) {
return false;
}
if (!isVariant(event.marketType, 'perp')) {
return false;
}
if (!isVariant(event.action, 'fill')) {
return false;
}
return true;
};
const fillCallback = (event) => {
console.log(event);
}
eventSubscriber.eventEmitter.on('newEvent', (event) => {
if (isPerpMarketFill(event)) {
fillCallback(event);
}
});
Getting Events Received By Type
const eventType = 'OrderActionRecord';
const events = eventSubscriber.getEventsReceived(eventType);
This returns all the events that the event subscriber currently has stored in memory.
Getting Events By Transaction
const txSig = '3dq5PtQ3VnNTkQRrHhQ1nRACWZaFVvSBKs1RLXM8WvCqLHTzTuVGc7XER5awoLFLTdJ4kqZiNmo7e8b3pXaEGaoo';
const events = eventSubscriber.getEventsByTx(txSig);
This returns the events that the event subscriber currently has stored in memory for a given transaction.
Margin System
Drift offers a cross-collateral margining system, allowing users to utilize multiple assets as trading collateral.
The margining system tracks each user's total collateral, the weighted sum of the user's deposits and perp pnl, as well as their margin requirement, the weighted value out the user's outstanding borrow and perp positions.
Total collateral is calculated as:
\[\sum_{i=1}^n d_i \cdot p_i \cdot w_i^a\ +\ \sum_{j=1}^n pnl_j \cdot qp_j \cdot w_j^{pnl} \]
Where
- \(d_i\) is the deposit amount for spot market \(i\)
- \(p_i\) is the price for spot market \(i\)
- \(w_i^a\) is the asset weight for spot market \(i\)
- \(pnl_j\) is the pnl for perp market \(j\)
- \(qp_j\) is the quote asset price for perp market \(j\)
- \(w_j^{pnl}\) is the pnl weight for perp market \(j\)
Margin requirement is calculated as:
\[ \sum_{i=1}^n b_i \cdot p_i \cdot w_i^l\ +\ \sum_{j=1}^n ba_j \cdot o_j \cdot qp_j \cdot m_j \]
Where
- \(b_i\) is the borrow amount for spot market \(i\)
- \(p_i\) is the price for spot market \(i\)
- \(w_i^l\) is the liability weight for spot market \(i\)
- \(ba_j\) is the base amount for perp market \(j\)
- \(o_j\) is the oracle price for perp market \(j\)
- \(qp_j\) is the quote asset price for perp market \(j\)
- \(m_j\) is the margin ratio for perp market \(j\)
The weights and margin ratios depend on whether you're calculating the initial or maintenance values.
The initial maintenance check governs leverage extension. To open a new perp position or borrow, a user's initial total collateral must be greater than their initial margin requirement.
The maintenance check governs when a user's position must be liquidated. If a user's maintenance total collateral drops below their maintenance margin requirement, a user's position can be liquidated to reduce their risk.
The prices used for deposits, borrows and perp quote assets differ between the initial and maintenance checks. The maintenance check uses
the current oracle price. The initial check uses the min(oracle_price, oracle_twap)
for deposits and positive perp pnl and max(oracle_price, oracle_twap)
for borrows, negative perp pnl and perp base amount.
Numerical Precisions
To maintain numerical precision, the on-chain program stores all values as integers.
Getting a Current Perp Position
const perpMarketIndex = 0; // SOL-PERP
const perpPosition = driftClient.getPerpPosition(perpMarketIndex);
console.log(convertToNumber(perpPosition.baseAssetAmount, BASE_PRECISION));
This prints the size of the current perp position in perp market index 0 (SOL-PERP)
Getting a Current Spot Position
const spotMarketIndex = 0; // USDC
const spotConfig = SpotMarkets['mainnet-beta'][spotMarketIndex];
const spotMarket = driftClient.getSpotMarketAccount(spotMarketIndex);
const spotPosition = driftClient.getSpotPosition(spotMarketIndex);
const tokenAmount = getTokenAmount(spotPosition.scaledBalance, spotMarket, .spotPosition.balanceType);
console.log(convertToNumber(tokenAmount, spotConfig.precision));
This prints the current spot position in spot market index 0 (USDC). This value is the same as the value shown on the UI, it includes any accumulated interest.
Common precision values
Value | Precision | Constant |
---|---|---|
perp base asset amount | 1e9 | BASE_PRECISION |
perp quote asset amount | 1e6 | QUOTE_PRECISION |
price | 1e6 | PRICE_PRECISION |
funding rate | 1e9 | FUNDING_RATE_PRECISION |
spot token amount | derived from token mint's decimals (USDC is 1e6, SOL is 1e9) | SpotMarketConfig.precision |
spot token balance | 1e9 | SPOT_MARKET_BALANCE_PRECISION |
margin ratio | 1e4 | MARGIN_PRECISION |
asset/liability weight | 1e4 | SPOT_WEIGHT_PRECISION |
Examples Bots
Typescript
Perp Markets
- perp filler
- floating maker
- jit maker
- funding rate update
- pnl settler
Spot Markets
- spot filler
- insurance fund revenue settler
Python
Historical Data
Snapshots are collected by parsing on-chain transaction logs. For convience the below are parsed logs collected, stored as a CSV, and stored off-chain (~99% of records).
Please share any transaction signatures or time ranges you believe might be missing in Drift Protocol Discord.
URL Prefix
mainnet-beta: https://drift-historical-data.s3.eu-west-1.amazonaws.com/program/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH/
devnet: https://drift-historical-data.s3.us-east-1.amazonaws.com/program/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH/
URL Suffix
Schema
recordType | url suffix |
---|---|
trades | user/${accountKey}/trades/${year}/${month} |
market-trades | market/${marketSymbol}/trades/${year}/${month}/${day} |
funding-rates | market/${marketSymbol}/funding-rates/${year}/${month} |
funding-payments | user/${accountKey}/funding-payments/${year}/${month} |
deposits | user/${accountKey}/deposits/${year}/${month} |
liquidations | user/${accountKey}/liquidations/${year}/${month} |
candles | market/${marketSymbol}/candles/${year}/${month}/resolution/${candleResolution} |
settle-pnl-records | user/${accountKey}/settlePnls/${year}/${month} |
Variables
variable | description | example |
---|---|---|
accountKey | user sub account public key (not authority) | |
marketSymbol | market name | SOL-PERP |
year | 2023 | |
month | 4 | |
day | utc time | 25 |
candleResolution | 1M |
Examples
import requests
outcsv = requets.get('https://drift-historical-data.s3.eu-west-1.amazonaws.com/program/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH/user/2dy78vpWpquDgAoLB8w8Ewfns9WXYzQx4CGt3HSgZLEe/trades/2023/4')'
curl https://drift-historical-data.s3.eu-west-1.amazonaws.com/program/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH/user/2dy78vpWpquDgAoLB8w8Ewfns9WXYzQx4CGt3HSgZLEe/trades/2023/4 --output out.csv.gz
Errors
Drift Protocol uses has following error codes:
code | name | msg |
---|---|---|
6000 | InvalidSpotMarketAuthority | Invalid Spot Market Authority |
6001 | InvalidInsuranceFundAuthority | Clearing house not insurance fund authority |
6002 | InsufficientDeposit | Insufficient deposit |
6003 | InsufficientCollateral | Insufficient collateral |
6004 | SufficientCollateral | Sufficient collateral |
6005 | MaxNumberOfPositions | Max number of positions taken |
6006 | AdminControlsPricesDisabled | Admin Controls Prices Disabled |
6007 | MarketDelisted | Market Delisted |
6008 | MarketIndexAlreadyInitialized | Market Index Already Initialized |
6009 | UserAccountAndUserPositionsAccountMismatch | User Account And User Positions Account Mismatch |
6010 | UserHasNoPositionInMarket | User Has No Position In Market |
6011 | InvalidInitialPeg | Invalid Initial Peg |
6012 | InvalidRepegRedundant | AMM repeg already configured with amt given |
6013 | InvalidRepegDirection | AMM repeg incorrect repeg direction |
6014 | InvalidRepegProfitability | AMM repeg out of bounds pnl |
6015 | SlippageOutsideLimit | Slippage Outside Limit Price |
6016 | OrderSizeTooSmall | Order Size Too Small |
6017 | InvalidUpdateK | Price change too large when updating K |
6018 | AdminWithdrawTooLarge | Admin tried to withdraw amount larger than fees collected |
6019 | MathError | Math Error |
6020 | BnConversionError | Conversion to u128/u64 failed with an overflow or underflow |
6021 | ClockUnavailable | Clock unavailable |
6022 | UnableToLoadOracle | Unable To Load Oracles |
6023 | PriceBandsBreached | Price Bands Breached |
6024 | ExchangePaused | Exchange is paused |
6025 | InvalidWhitelistToken | Invalid whitelist token |
6026 | WhitelistTokenNotFound | Whitelist token not found |
6027 | InvalidDiscountToken | Invalid discount token |
6028 | DiscountTokenNotFound | Discount token not found |
6029 | ReferrerNotFound | Referrer not found |
6030 | ReferrerStatsNotFound | ReferrerNotFound |
6031 | ReferrerMustBeWritable | ReferrerMustBeWritable |
6032 | ReferrerStatsMustBeWritable | ReferrerMustBeWritable |
6033 | ReferrerAndReferrerStatsAuthorityUnequal | ReferrerAndReferrerStatsAuthorityUnequal |
6034 | InvalidReferrer | InvalidReferrer |
6035 | InvalidOracle | InvalidOracle |
6036 | OracleNotFound | OracleNotFound |
6037 | LiquidationsBlockedByOracle | Liquidations Blocked By Oracle |
6038 | MaxDeposit | Can not deposit more than max deposit |
6039 | CantDeleteUserWithCollateral | Can not delete user that still has collateral |
6040 | InvalidFundingProfitability | AMM funding out of bounds pnl |
6041 | CastingFailure | Casting Failure |
6042 | InvalidOrder | InvalidOrder |
6043 | InvalidOrderMaxTs | InvalidOrderMaxTs |
6044 | InvalidOrderMarketType | InvalidOrderMarketType |
6045 | InvalidOrderForInitialMarginReq | InvalidOrderForInitialMarginReq |
6046 | InvalidOrderNotRiskReducing | InvalidOrderNotRiskReducing |
6047 | InvalidOrderSizeTooSmall | InvalidOrderSizeTooSmall |
6048 | InvalidOrderNotStepSizeMultiple | InvalidOrderNotStepSizeMultiple |
6049 | InvalidOrderBaseQuoteAsset | InvalidOrderBaseQuoteAsset |
6050 | InvalidOrderIOC | InvalidOrderIOC |
6051 | InvalidOrderPostOnly | InvalidOrderPostOnly |
6052 | InvalidOrderIOCPostOnly | InvalidOrderIOCPostOnly |
6053 | InvalidOrderTrigger | InvalidOrderTrigger |
6054 | InvalidOrderAuction | InvalidOrderAuction |
6055 | InvalidOrderOracleOffset | InvalidOrderOracleOffset |
6056 | InvalidOrderMinOrderSize | InvalidOrderMinOrderSize |
6057 | PlacePostOnlyLimitFailure | Failed to Place Post-Only Limit Order |
6058 | UserHasNoOrder | User has no order |
6059 | OrderAmountTooSmall | Order Amount Too Small |
6060 | MaxNumberOfOrders | Max number of orders taken |
6061 | OrderDoesNotExist | Order does not exist |
6062 | OrderNotOpen | Order not open |
6063 | FillOrderDidNotUpdateState | FillOrderDidNotUpdateState |
6064 | ReduceOnlyOrderIncreasedRisk | Reduce only order increased risk |
6065 | UnableToLoadAccountLoader | Unable to load AccountLoader |
6066 | TradeSizeTooLarge | Trade Size Too Large |
6067 | UserCantReferThemselves | User cant refer themselves |
6068 | DidNotReceiveExpectedReferrer | Did not receive expected referrer |
6069 | CouldNotDeserializeReferrer | Could not deserialize referrer |
6070 | CouldNotDeserializeReferrerStats | Could not deserialize referrer stats |
6071 | UserOrderIdAlreadyInUse | User Order Id Already In Use |
6072 | NoPositionsLiquidatable | No positions liquidatable |
6073 | InvalidMarginRatio | Invalid Margin Ratio |
6074 | CantCancelPostOnlyOrder | Cant Cancel Post Only Order |
6075 | InvalidOracleOffset | InvalidOracleOffset |
6076 | CantExpireOrders | CantExpireOrders |
6077 | CouldNotLoadMarketData | CouldNotLoadMarketData |
6078 | PerpMarketNotFound | PerpMarketNotFound |
6079 | InvalidMarketAccount | InvalidMarketAccount |
6080 | UnableToLoadPerpMarketAccount | UnableToLoadMarketAccount |
6081 | MarketWrongMutability | MarketWrongMutability |
6082 | UnableToCastUnixTime | UnableToCastUnixTime |
6083 | CouldNotFindSpotPosition | CouldNotFindSpotPosition |
6084 | NoSpotPositionAvailable | NoSpotPositionAvailable |
6085 | InvalidSpotMarketInitialization | InvalidSpotMarketInitialization |
6086 | CouldNotLoadSpotMarketData | CouldNotLoadSpotMarketData |
6087 | SpotMarketNotFound | SpotMarketNotFound |
6088 | InvalidSpotMarketAccount | InvalidSpotMarketAccount |
6089 | UnableToLoadSpotMarketAccount | UnableToLoadSpotMarketAccount |
6090 | SpotMarketWrongMutability | SpotMarketWrongMutability |
6091 | SpotMarketInterestNotUpToDate | SpotInterestNotUpToDate |
6092 | SpotMarketInsufficientDeposits | SpotMarketInsufficientDeposits |
6093 | UserMustSettleTheirOwnPositiveUnsettledPNL | UserMustSettleTheirOwnPositiveUnsettledPNL |
6094 | CantUpdatePoolBalanceType | CantUpdatePoolBalanceType |
6095 | InsufficientCollateralForSettlingPNL | InsufficientCollateralForSettlingPNL |
6096 | AMMNotUpdatedInSameSlot | AMMNotUpdatedInSameSlot |
6097 | AuctionNotComplete | AuctionNotComplete |
6098 | MakerNotFound | MakerNotFound |
6099 | MakerStatsNotFound | MakerNotFound |
6100 | MakerMustBeWritable | MakerMustBeWritable |
6101 | MakerStatsMustBeWritable | MakerMustBeWritable |
6102 | MakerOrderNotFound | MakerOrderNotFound |
6103 | CouldNotDeserializeMaker | CouldNotDeserializeMaker |
6104 | CouldNotDeserializeMakerStats | CouldNotDeserializeMaker |
6105 | AuctionPriceDoesNotSatisfyMaker | AuctionPriceDoesNotSatisfyMaker |
6106 | MakerCantFulfillOwnOrder | MakerCantFulfillOwnOrder |
6107 | MakerOrderMustBePostOnly | MakerOrderMustBePostOnly |
6108 | CantMatchTwoPostOnlys | CantMatchTwoPostOnlys |
6109 | OrderBreachesOraclePriceLimits | OrderBreachesOraclePriceLimits |
6110 | OrderMustBeTriggeredFirst | OrderMustBeTriggeredFirst |
6111 | OrderNotTriggerable | OrderNotTriggerable |
6112 | OrderDidNotSatisfyTriggerCondition | OrderDidNotSatisfyTriggerCondition |
6113 | PositionAlreadyBeingLiquidated | PositionAlreadyBeingLiquidated |
6114 | PositionDoesntHaveOpenPositionOrOrders | PositionDoesntHaveOpenPositionOrOrders |
6115 | AllOrdersAreAlreadyLiquidations | AllOrdersAreAlreadyLiquidations |
6116 | CantCancelLiquidationOrder | CantCancelLiquidationOrder |
6117 | UserIsBeingLiquidated | UserIsBeingLiquidated |
6118 | LiquidationsOngoing | LiquidationsOngoing |
6119 | WrongSpotBalanceType | WrongSpotBalanceType |
6120 | UserCantLiquidateThemself | UserCantLiquidateThemself |
6121 | InvalidPerpPositionToLiquidate | InvalidPerpPositionToLiquidate |
6122 | InvalidBaseAssetAmountForLiquidatePerp | InvalidBaseAssetAmountForLiquidatePerp |
6123 | InvalidPositionLastFundingRate | InvalidPositionLastFundingRate |
6124 | InvalidPositionDelta | InvalidPositionDelta |
6125 | UserBankrupt | UserBankrupt |
6126 | UserNotBankrupt | UserNotBankrupt |
6127 | UserHasInvalidBorrow | UserHasInvalidBorrow |
6128 | DailyWithdrawLimit | DailyWithdrawLimit |
6129 | DefaultError | DefaultError |
6130 | InsufficientLPTokens | Insufficient LP tokens |
6131 | CantLPWithPerpPosition | Cant LP with a market position |
6132 | UnableToBurnLPTokens | Unable to burn LP tokens |
6133 | TryingToRemoveLiquidityTooFast | Trying to remove liqudity too fast after adding it |
6134 | InvalidSpotMarketVault | Invalid Spot Market Vault |
6135 | InvalidSpotMarketState | Invalid Spot Market State |
6136 | InvalidSerumProgram | InvalidSerumProgram |
6137 | InvalidSerumMarket | InvalidSerumMarket |
6138 | InvalidSerumBids | InvalidSerumBids |
6139 | InvalidSerumAsks | InvalidSerumAsks |
6140 | InvalidSerumOpenOrders | InvalidSerumOpenOrders |
6141 | FailedSerumCPI | FailedSerumCPI |
6142 | FailedToFillOnExternalMarket | FailedToFillOnExternalMarket |
6143 | InvalidFulfillmentConfig | InvalidFulfillmentConfig |
6144 | InvalidFeeStructure | InvalidFeeStructure |
6145 | InsufficientIFShares | Insufficient IF shares |
6146 | MarketActionPaused | the Market has paused this action |
6147 | MarketPlaceOrderPaused | the Market status doesnt allow placing orders |
6148 | MarketFillOrderPaused | the Market status doesnt allow filling orders |
6149 | MarketWithdrawPaused | the Market status doesnt allow withdraws |
6150 | ProtectedAssetTierViolation | Action violates the Protected Asset Tier rules |
6151 | IsolatedAssetTierViolation | Action violates the Isolated Asset Tier rules |
6152 | UserCantBeDeleted | User Cant Be Deleted |
6153 | ReduceOnlyWithdrawIncreasedRisk | Reduce Only Withdraw Increased Risk |
6154 | MaxOpenInterest | Max Open Interest |
6155 | CantResolvePerpBankruptcy | Cant Resolve Perp Bankruptcy |
6156 | LiquidationDoesntSatisfyLimitPrice | Liquidation Doesnt Satisfy Limit Price |
6157 | MarginTradingDisabled | Margin Trading Disabled |
6158 | InvalidMarketStatusToSettlePnl | Invalid Market Status to Settle Perp Pnl |
6159 | PerpMarketNotInSettlement | PerpMarketNotInSettlement |
6160 | PerpMarketNotInReduceOnly | PerpMarketNotInReduceOnly |
6161 | PerpMarketSettlementBufferNotReached | PerpMarketSettlementBufferNotReached |
6162 | PerpMarketSettlementUserHasOpenOrders | PerpMarketSettlementUserHasOpenOrders |
6163 | PerpMarketSettlementUserHasActiveLP | PerpMarketSettlementUserHasActiveLP |
6164 | UnableToSettleExpiredUserPosition | UnableToSettleExpiredUserPosition |
6165 | UnequalMarketIndexForSpotTransfer | UnequalMarketIndexForSpotTransfer |
6166 | InvalidPerpPositionDetected | InvalidPerpPositionDetected |
6167 | InvalidSpotPositionDetected | InvalidSpotPositionDetected |
6168 | InvalidAmmDetected | InvalidAmmDetected |
6169 | InvalidAmmForFillDetected | InvalidAmmForFillDetected |
6170 | InvalidAmmLimitPriceOverride | InvalidAmmLimitPriceOverride |
6171 | InvalidOrderFillPrice | InvalidOrderFillPrice |
6172 | SpotMarketBalanceInvariantViolated | SpotMarketBalanceInvariantViolated |
6173 | SpotMarketVaultInvariantViolated | SpotMarketVaultInvariantViolated |
6174 | InvalidPDA | InvalidPDA |
6175 | InvalidPDASigner | InvalidPDASigner |
6176 | RevenueSettingsCannotSettleToIF | RevenueSettingsCannotSettleToIF |
6177 | NoRevenueToSettleToIF | NoRevenueToSettleToIF |
6178 | NoAmmPerpPnlDeficit | NoAmmPerpPnlDeficit |
6179 | SufficientPerpPnlPool | SufficientPerpPnlPool |
6180 | InsufficientPerpPnlPool | InsufficientPerpPnlPool |
6181 | PerpPnlDeficitBelowThreshold | PerpPnlDeficitBelowThreshold |
6182 | MaxRevenueWithdrawPerPeriodReached | MaxRevenueWithdrawPerPeriodReached |
6183 | MaxIFWithdrawReached | InvalidSpotPositionDetected |
6184 | NoIFWithdrawAvailable | NoIFWithdrawAvailable |
6185 | InvalidIFUnstake | InvalidIFUnstake |
6186 | InvalidIFUnstakeSize | InvalidIFUnstakeSize |
6187 | InvalidIFUnstakeCancel | InvalidIFUnstakeCancel |
6188 | InvalidIFForNewStakes | InvalidIFForNewStakes |
6189 | InvalidIFRebase | InvalidIFRebase |
6190 | InvalidInsuranceUnstakeSize | InvalidInsuranceUnstakeSize |
6191 | InvalidOrderLimitPrice | InvalidOrderLimitPrice |
6192 | InvalidIFDetected | InvalidIFDetected |
6193 | InvalidAmmMaxSpreadDetected | InvalidAmmMaxSpreadDetected |
6194 | InvalidConcentrationCoef | InvalidConcentrationCoef |
6195 | InvalidSrmVault | InvalidSrmVault |
6196 | InvalidVaultOwner | InvalidVaultOwner |
6197 | InvalidMarketStatusForFills | InvalidMarketStatusForFills |
6198 | IFWithdrawRequestInProgress | IFWithdrawRequestInProgress |
6199 | NoIFWithdrawRequestInProgress | NoIFWithdrawRequestInProgress |
6200 | IFWithdrawRequestTooSmall | IFWithdrawRequestTooSmall |
6201 | IncorrectSpotMarketAccountPassed | IncorrectSpotMarketAccountPassed |
6202 | BlockchainClockInconsistency | BlockchainClockInconsistency |
6203 | InvalidIFSharesDetected | InvalidIFSharesDetected |
6204 | NewLPSizeTooSmall | NewLPSizeTooSmall |
6205 | MarketStatusInvalidForNewLP | MarketStatusInvalidForNewLP |
6206 | InvalidMarkTwapUpdateDetected | InvalidMarkTwapUpdateDetected |
6207 | MarketSettlementAttemptOnActiveMarket | MarketSettlementAttemptOnActiveMarket |
6208 | MarketSettlementRequiresSettledLP | MarketSettlementRequiresSettledLP |
6209 | MarketSettlementAttemptTooEarly | MarketSettlementAttemptTooEarly |
6210 | MarketSettlementTargetPriceInvalid | MarketSettlementTargetPriceInvalid |
6211 | UnsupportedSpotMarket | UnsupportedSpotMarket |
6212 | SpotOrdersDisabled | SpotOrdersDisabled |
6213 | MarketBeingInitialized | Market Being Initialized |
6214 | InvalidUserSubAccountId | Invalid Sub Account Id |
6215 | InvalidTriggerOrderCondition | Invalid Trigger Order Condition |
6216 | InvalidSpotPosition | Invalid Spot Position |
6217 | CantTransferBetweenSameUserAccount | Cant transfer between same user account |
6218 | InvalidPerpPosition | Invalid Perp Position |
6219 | UnableToGetLimitPrice | Unable To Get Limit Price |
6220 | InvalidLiquidation | Invalid Liquidation |
6221 | SpotFulfillmentConfigDisabled | Spot Fulfullment Config Disabled |
6222 | InvalidMaker | Invalid Maker |
6223 | FailedUnwrap | Failed Unwrap |
6224 | MaxNumberOfUsers | Max Number Of Users |
6225 | InvalidOracleForSettlePnl | InvalidOracleForSettlePnl |
6226 | MarginOrdersOpen | MarginOrdersOpen |
6227 | TierViolationLiquidatingPerpPnl | TierViolationLiquidatingPerpPnl |
6228 | CouldNotLoadUserData | CouldNotLoadUserData |
6229 | UserWrongMutability | UserWrongMutability |
6230 | InvalidUserAccount | InvalidUserAccount |
6231 | CouldNotLoadUserStatsData | CouldNotLoadUserData |
6232 | UserStatsWrongMutability | UserWrongMutability |
6233 | InvalidUserStatsAccount | InvalidUserAccount |
6234 | UserNotFound | UserNotFound |
6235 | UnableToLoadUserAccount | UnableToLoadUserAccount |
6236 | UserStatsNotFound | UserStatsNotFound |
6237 | UnableToLoadUserStatsAccount | UnableToLoadUserStatsAccount |
6238 | UserNotInactive | User Not Inactive |
6239 | RevertFill | RevertFill |
6240 | InvalidMarketAccountforDeletion | Invalid MarketAccount for Deletion |
6241 | InvalidSpotFulfillmentParams | Invalid Spot Fulfillment Params |
6242 | FailedToGetMint | Failed to Get Mint |
6243 | FailedPhoenixCPI | FailedPhoenixCPI |
6244 | FailedToDeserializePhoenixMarket | FailedToDeserializePhoenixMarket |
6245 | InvalidPricePrecision | InvalidPricePrecision |
6246 | InvalidPhoenixProgram | InvalidPhoenixProgram |
6247 | InvalidPhoenixMarket | InvalidPhoenixMarket |