UNPKG

@drift-labs/sdk-browser

Version:
391 lines (355 loc) 10.4 kB
import { BN } from '@coral-xyz/anchor'; import { MarginMode, MarketType, Order, OrderStatus, OrderTriggerCondition, OrderType, PerpPosition, PositionDirection, SpotBalanceType, SpotPosition, UserAccount, } from '../types'; import { PublicKey } from '@solana/web3.js'; import { ZERO } from '../constants/numericConstants'; function readUnsignedBigInt64LE(buffer: Buffer, offset: number): BN { return new BN(buffer.subarray(offset, offset + 8), 10, 'le'); } function readSignedBigInt64LE(buffer: Buffer, offset: number): BN { const unsignedValue = new BN(buffer.subarray(offset, offset + 8), 10, 'le'); if (unsignedValue.testn(63)) { const inverted = unsignedValue.notn(64).addn(1); return inverted.neg(); } else { return unsignedValue; } } export function decodeUser(buffer: Buffer): UserAccount { let offset = 8; const authority = new PublicKey(buffer.slice(offset, offset + 32)); offset += 32; const delegate = new PublicKey(buffer.slice(offset, offset + 32)); offset += 32; const name = []; for (let i = 0; i < 32; i++) { name.push(buffer.readUint8(offset + i)); } offset += 32; const spotPositions: SpotPosition[] = []; for (let i = 0; i < 8; i++) { const scaledBalance = readUnsignedBigInt64LE(buffer, offset); const openOrders = buffer.readUInt8(offset + 35); if (scaledBalance.eq(ZERO) && openOrders === 0) { offset += 40; continue; } offset += 8; const openBids = readSignedBigInt64LE(buffer, offset); offset += 8; const openAsks = readSignedBigInt64LE(buffer, offset); offset += 8; const cumulativeDeposits = readSignedBigInt64LE(buffer, offset); offset += 8; const marketIndex = buffer.readUInt16LE(offset); offset += 2; const balanceTypeNum = buffer.readUInt8(offset); let balanceType: SpotBalanceType; if (balanceTypeNum === 0) { balanceType = SpotBalanceType.DEPOSIT; } else { balanceType = SpotBalanceType.BORROW; } offset += 6; spotPositions.push({ scaledBalance, openBids, openAsks, cumulativeDeposits, marketIndex, balanceType, openOrders, }); } const perpPositions: PerpPosition[] = []; for (let i = 0; i < 8; i++) { const baseAssetAmount = readSignedBigInt64LE(buffer, offset + 8); const quoteAssetAmount = readSignedBigInt64LE(buffer, offset + 16); const lpShares = readUnsignedBigInt64LE(buffer, offset + 64); const openOrders = buffer.readUInt8(offset + 94); if ( baseAssetAmount.eq(ZERO) && openOrders === 0 && quoteAssetAmount.eq(ZERO) && lpShares.eq(ZERO) ) { offset += 96; continue; } const lastCumulativeFundingRate = readSignedBigInt64LE(buffer, offset); offset += 24; const quoteBreakEvenAmount = readSignedBigInt64LE(buffer, offset); offset += 8; const quoteEntryAmount = readSignedBigInt64LE(buffer, offset); offset += 8; const openBids = readSignedBigInt64LE(buffer, offset); offset += 8; const openAsks = readSignedBigInt64LE(buffer, offset); offset += 8; const settledPnl = readSignedBigInt64LE(buffer, offset); offset += 16; const lastBaseAssetAmountPerLp = readSignedBigInt64LE(buffer, offset); offset += 8; const lastQuoteAssetAmountPerLp = readSignedBigInt64LE(buffer, offset); offset += 8; const maxMarginRatio = buffer.readUInt16LE(offset); offset += 4; const marketIndex = buffer.readUInt16LE(offset); offset += 3; const perLpBase = buffer.readUInt8(offset); offset += 1; perpPositions.push({ lastCumulativeFundingRate, baseAssetAmount, quoteAssetAmount, quoteBreakEvenAmount, quoteEntryAmount, openBids, openAsks, settledPnl, lpShares, remainderBaseAssetAmount: 0, lastBaseAssetAmountPerLp, lastQuoteAssetAmountPerLp, marketIndex, openOrders, perLpBase, maxMarginRatio, }); } const orders: Order[] = []; for (let i = 0; i < 32; i++) { // skip order if it's not open if (buffer.readUint8(offset + 82) !== 1) { offset += 96; continue; } const slot = readUnsignedBigInt64LE(buffer, offset); offset += 8; const price = readUnsignedBigInt64LE(buffer, offset); offset += 8; const baseAssetAmount = readUnsignedBigInt64LE(buffer, offset); offset += 8; const baseAssetAmountFilled = readUnsignedBigInt64LE(buffer, offset); offset += 8; const quoteAssetAmountFilled = readUnsignedBigInt64LE(buffer, offset); offset += 8; const triggerPrice = readUnsignedBigInt64LE(buffer, offset); offset += 8; const auctionStartPrice = readSignedBigInt64LE(buffer, offset); offset += 8; const auctionEndPrice = readSignedBigInt64LE(buffer, offset); offset += 8; const maxTs = readSignedBigInt64LE(buffer, offset); offset += 8; const oraclePriceOffset = buffer.readInt32LE(offset); offset += 4; const orderId = buffer.readUInt32LE(offset); offset += 4; const marketIndex = buffer.readUInt16LE(offset); offset += 2; const orderStatusNum = buffer.readUInt8(offset); let status: OrderStatus; if (orderStatusNum === 0) { status = OrderStatus.INIT; } else if (orderStatusNum === 1) { status = OrderStatus.OPEN; } offset += 1; const orderTypeNum = buffer.readUInt8(offset); let orderType: OrderType; if (orderTypeNum === 0) { orderType = OrderType.MARKET; } else if (orderTypeNum === 1) { orderType = OrderType.LIMIT; } else if (orderTypeNum === 2) { orderType = OrderType.TRIGGER_MARKET; } else if (orderTypeNum === 3) { orderType = OrderType.TRIGGER_LIMIT; } else if (orderTypeNum === 4) { orderType = OrderType.ORACLE; } offset += 1; const marketTypeNum = buffer.readUInt8(offset); let marketType: MarketType; if (marketTypeNum === 0) { marketType = MarketType.SPOT; } else { marketType = MarketType.PERP; } offset += 1; const userOrderId = buffer.readUint8(offset); offset += 1; const existingPositionDirectionNum = buffer.readUInt8(offset); let existingPositionDirection: PositionDirection; if (existingPositionDirectionNum === 0) { existingPositionDirection = PositionDirection.LONG; } else { existingPositionDirection = PositionDirection.SHORT; } offset += 1; const positionDirectionNum = buffer.readUInt8(offset); let direction: PositionDirection; if (positionDirectionNum === 0) { direction = PositionDirection.LONG; } else { direction = PositionDirection.SHORT; } offset += 1; const reduceOnly = buffer.readUInt8(offset) === 1; offset += 1; const postOnly = buffer.readUInt8(offset) === 1; offset += 1; const immediateOrCancel = buffer.readUInt8(offset) === 1; offset += 1; const triggerConditionNum = buffer.readUInt8(offset); let triggerCondition: OrderTriggerCondition; if (triggerConditionNum === 0) { triggerCondition = OrderTriggerCondition.ABOVE; } else if (triggerConditionNum === 1) { triggerCondition = OrderTriggerCondition.BELOW; } else if (triggerConditionNum === 2) { triggerCondition = OrderTriggerCondition.TRIGGERED_ABOVE; } else if (triggerConditionNum === 3) { triggerCondition = OrderTriggerCondition.TRIGGERED_BELOW; } offset += 1; const auctionDuration = buffer.readUInt8(offset); offset += 1; const postedSlotTail = buffer.readUint8(offset); offset += 1; const bitFlags = buffer.readUint8(offset); offset += 1; offset += 1; // padding orders.push({ slot, price, baseAssetAmount, quoteAssetAmount: undefined, baseAssetAmountFilled, quoteAssetAmountFilled, triggerPrice, auctionStartPrice, auctionEndPrice, maxTs, oraclePriceOffset, orderId, marketIndex, status, orderType, marketType, userOrderId, existingPositionDirection, direction, reduceOnly, postOnly, immediateOrCancel, triggerCondition, auctionDuration, bitFlags, postedSlotTail, }); } const lastAddPerpLpSharesTs = readSignedBigInt64LE(buffer, offset); offset += 8; const totalDeposits = readUnsignedBigInt64LE(buffer, offset); offset += 8; const totalWithdraws = readUnsignedBigInt64LE(buffer, offset); offset += 8; const totalSocialLoss = readUnsignedBigInt64LE(buffer, offset); offset += 8; const settledPerpPnl = readSignedBigInt64LE(buffer, offset); offset += 8; const cumulativeSpotFees = readSignedBigInt64LE(buffer, offset); offset += 8; const cumulativePerpFunding = readSignedBigInt64LE(buffer, offset); offset += 8; const liquidationMarginFreed = readUnsignedBigInt64LE(buffer, offset); offset += 8; const lastActiveSlot = readUnsignedBigInt64LE(buffer, offset); offset += 8; const nextOrderId = buffer.readUInt32LE(offset); offset += 4; const maxMarginRatio = buffer.readUInt32LE(offset); offset += 4; const nextLiquidationId = buffer.readUInt16LE(offset); offset += 2; const subAccountId = buffer.readUInt16LE(offset); offset += 2; const status = buffer.readUInt8(offset); offset += 1; const isMarginTradingEnabled = buffer.readUInt8(offset) === 1; offset += 1; const idle = buffer.readUInt8(offset) === 1; offset += 1; const openOrders = buffer.readUInt8(offset); offset += 1; const hasOpenOrder = buffer.readUInt8(offset) === 1; offset += 1; const openAuctions = buffer.readUInt8(offset); offset += 1; const hasOpenAuction = buffer.readUInt8(offset) === 1; offset += 1; let marginMode: MarginMode; const marginModeNum = buffer.readUInt8(offset); if (marginModeNum === 0) { marginMode = MarginMode.DEFAULT; } else if (marginModeNum === 1) { marginMode = MarginMode.HIGH_LEVERAGE; } else if (marginModeNum === 2) { marginMode = MarginMode.HIGH_LEVERAGE_MAINTENANCE; } else { console.error( `Detected unknown margin mode: ${marginModeNum}. Please update @drift-labs/sdk for latest IDL.` ); marginMode = MarginMode.DEFAULT; } offset += 1; const poolId = buffer.readUint8(offset); offset += 1; offset += 3; // padding const lastFuelBonusUpdateTs = buffer.readUint32LE(offset); offset += 4; return { authority, delegate, name, spotPositions, perpPositions, orders, lastAddPerpLpSharesTs, totalDeposits, totalWithdraws, totalSocialLoss, settledPerpPnl, cumulativeSpotFees, cumulativePerpFunding, liquidationMarginFreed, lastActiveSlot, nextOrderId, maxMarginRatio, nextLiquidationId, subAccountId, status, isMarginTradingEnabled, idle, openOrders, hasOpenOrder, openAuctions, hasOpenAuction, marginMode, poolId, lastFuelBonusUpdateTs, }; }