UNPKG

@d8x/perpetuals-sdk

Version:

Node TypeScript SDK for D8X Perpetual Futures

574 lines (573 loc) 28 kB
import { BaseContract, Contract, Interface, Network, Overrides, Provider, Signer } from "ethers"; import { LimitOrderBook, LimitOrderBookFactory, Multicall3 } from "./contracts"; import { IPerpetualManager } from "./contracts/IPerpetualManager"; import { IClientOrder, IPerpetualOrder } from "./contracts/LimitOrderBook"; import { TypeSafeOrder, type ClientOrder, type MarginAccount, type NodeSDKConfig, type Order, type PerpetualState, type PerpetualStaticInfo, type PoolStaticInfo, type PriceFeedSubmission, type SmartContractOrder, type PerpetualData, LiquidityPoolData, SettlementConfig, IdxPriceInfo } from "./nodeSDKTypes"; import PriceFeeds from "./priceFeeds"; /** * Parent class for MarketData and WriteAccessHandler that handles * common data and chain operations. */ export default class PerpetualDataHandler { PRICE_UPDATE_FEE_GWEI: number; protected symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>; protected perpetualIdToSymbol: Map<number, string>; protected poolStaticInfos: Array<PoolStaticInfo>; protected symbolList: Map<string, string>; protected settlementConfig: SettlementConfig; requiredSymbols: string[]; config: NodeSDKConfig; protected symbolToTokenAddrMap: Map<string, string>; chainId: bigint; network: Network; protected proxyContract: IPerpetualManager | null; protected proxyABI: Interface; protected proxyAddr: string; protected oraclefactoryAddr: string | undefined; protected lobFactoryContract: LimitOrderBookFactory | null; protected lobFactoryABI: Interface; protected lobFactoryAddr: string | undefined; protected lobABI: Interface; protected shareTokenABI: Interface; protected multicall: Multicall3 | null; protected nodeURL: string; protected provider: Provider | null; protected pythAddr: string | undefined; protected signerOrProvider: Signer | Provider | null; protected priceFeedGetter: PriceFeeds; protected nestedPerpetualIDs: number[][]; /** * Constructor * @param {NodeSDKConfig} config Configuration object, see * PerpetualDataHandler.readSDKConfig. */ constructor(config: NodeSDKConfig); protected initContractsAndData(signerOrProvider: Signer | Provider, overrides?: Overrides): Promise<void>; /** * sets the symbollist if a remote config url is specified */ private fetchSymbolList; /** * Returns the order-book contract for the symbol if found or fails * @param symbol symbol of the form ETH-USD-MATIC * @returns order book contract for the perpetual */ getOrderBookContract(symbol: string, signerOrProvider?: Signer | Provider): LimitOrderBook; /** * Returns the order-book contract for the symbol if found or fails * @param symbol symbol of the form ETH-USD-MATIC * @returns order book contract for the perpetual */ getOrderBookAddress(symbol: string): string | undefined; /** * Get perpetuals for the given ids from onchain * @param ids perpetual ids * @param overrides optional * @returns array of PerpetualData converted into decimals */ getPerpetuals(ids: number[], overrides?: Overrides): Promise<PerpetualData[]>; /** * Get liquidity pools data * @param fromIdx starting index (>=1) * @param toIdx to index (inclusive) * @param overrides optional * @returns array of LiquidityPoolData converted into decimals */ getLiquidityPools(fromIdx: number, toIdx: number, overrides?: Overrides): Promise<LiquidityPoolData[]>; /** * Called when initializing. This function fills this.symbolToTokenAddrMap, * and this.nestedPerpetualIDs and this.symbolToPerpStaticInfo * */ protected _fillSymbolMaps(overrides?: Overrides): Promise<void>; private setRequiredSymbols; /** * Initializes settlement currency for all pools by * completing this.poolStaticInfos with settlement currency info * @param perpStaticInfos PerpetualStaticInfo array from contract call */ private initSettlementToken; /** * Utility function to export mapping and re-use in other objects. * @ignore */ getAllMappings(): { nestedPerpetualIDs: number[][]; poolStaticInfos: PoolStaticInfo[]; symbolToTokenAddrMap: Map<string, string>; symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>; perpetualIdToSymbol: Map<number, string>; }; /** * Get pool symbol given a pool Id. * @param {number} poolId Pool Id. * @returns {symbol} Pool symbol, e.g. "USDC". */ getSymbolFromPoolId(poolId: number): string; /** * Get pool Id given a pool symbol. Pool IDs start at 1. * @param {string} symbol Pool symbol. * @returns {number} Pool Id. */ getPoolIdFromSymbol(symbol: string): number; /** * Get perpetual Id given a perpetual symbol. * @param {string} symbol Perpetual symbol, e.g. "BTC-USD-MATIC". * @returns {number} Perpetual Id. */ getPerpIdFromSymbol(symbol: string): number; /** * Get the symbol in long format of the perpetual id * @param {number} perpId perpetual id * @returns {string} Symbol */ getSymbolFromPerpId(perpId: number): string | undefined; /** * * @param {string} sym Short symbol * @returns {string} Long symbol */ symbol4BToLongSymbol(sym: string): string; /** * Get PriceFeedSubmission data required for blockchain queries that involve price data, and the corresponding * triangulated prices for the indices S2 and S3 * @param symbol pool symbol of the form "ETH-USD-MATIC" * @returns PriceFeedSubmission and prices for S2 and S3. [S2price, 0] if S3 not defined. */ fetchPriceSubmissionInfoForPerpetual(symbol: string): Promise<{ submission: PriceFeedSubmission; pxS2S3: [number, number]; }>; /** * Get the symbols required as indices for the given perpetual * @param symbol of the form ETH-USD-MATIC, specifying the perpetual * @returns name of underlying index prices, e.g. ["MATIC-USD", ""] */ getIndexSymbols(symbol: string): [string, string]; /** * Get the latest prices for a given perpetual from the offchain oracle * networks * @param symbol perpetual symbol of the form BTC-USD-MATIC * @returns array of price feed updates that can be submitted to the smart contract * and corresponding price information */ fetchLatestFeedPriceInfo(symbol: string): Promise<PriceFeedSubmission>; /** * fetchCollateralToSettlementConversion returns the price which converts the collateral * currency into settlement currency. For example if BTC-USD-STUSD has settlement currency * USDC, we get * let px = fetchCollateralToSettlementConversion("BTC-USD-STUSD") * valueInUSDC = collateralInSTUSD * px * @param symbol either perpetual symbol of the form BTC-USD-MATIC or just collateral token */ fetchCollateralToSettlementConversion(symbol: string): Promise<number>; /** * Get list of required pyth price source IDs for given perpetual * @param symbol perpetual symbol, e.g., BTC-USD-MATIC * @returns list of required pyth price sources for this perpetual */ getPriceIds(symbol: string): string[]; protected static _getSymbolFromPoolId(poolId: number, staticInfos: PoolStaticInfo[]): string; protected static _getPoolIdFromSymbol(symbol: string, staticInfos: PoolStaticInfo[]): number; /** * Get ('normal'-state) perpetual symbols for a given pool * @param poolSymbol pool symbol such as "MATIC" * @returns array of perpetual symbols in this pool */ getPerpetualSymbolsInPool(poolSymbol: string): string[]; getNestedPerpetualIds(): number[][]; /** * Collect all perpetuals static info * @param {ethers.Contract} _proxyContract perpetuals contract with getter * @param {Array<Array<number>>} nestedPerpetualIDs perpetual id-array for each pool * @param {Map<string, string>} symbolList mapping of symbols to convert long-format <-> blockchain-format * @returns array with PerpetualStaticInfo for each perpetual */ static getPerpetualStaticInfo(_proxyContract: IPerpetualManager, nestedPerpetualIDs: Array<Array<number>>, symbolList: Map<string, string>, overrides?: Overrides): Promise<Array<PerpetualStaticInfo>>; /** * Breaks up an array of nested arrays into chunks of a specified size. * @param {number} chunkSize The size of each chunk. * @param {number[][]} nestedIDs The array of nested arrays to chunk. * @returns {number[][]} An array of subarrays, each containing `chunkSize` or fewer elements from `nestedIDs`. */ static nestedIDsToChunks(chunkSize: number, nestedIDs: Array<Array<number>>): Array<Array<number>>; /** * Query perpetuals * @param ids perpetual ids * @param _proxyContract proxy contract instance * @param _symbolList symbol mappings to convert the bytes encoded symbol name to string * @param overrides optional * @returns array of PerpetualData converted into decimals */ static _getLiquidityPools(fromIdx: number, toIdx: number, _proxyContract: IPerpetualManager, _symbolList: Map<string, string>, overrides?: Overrides): Promise<LiquidityPoolData[]>; /** * Query perpetuals * @param ids perpetual ids * @param _proxyContract proxy contract instance * @param _symbolList symbol mappings to convert the bytes encoded symbol name to string * @param overrides optional * @returns array of PerpetualData converted into decimals */ static _getPerpetuals(ids: number[], _proxyContract: IPerpetualManager, _symbolList: Map<string, string>, overrides?: Overrides): Promise<PerpetualData[]>; static getPoolStaticInfo(_proxyContract: IPerpetualManager, overrides?: Overrides): Promise<{ nestedPerpetualIDs: Array<Array<number>>; poolShareTokenAddr: Array<string>; poolMarginTokenAddr: Array<string>; oracleFactory: string; }>; static buildMarginAccountFromState(symbol: string, traderState: bigint[], symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, pxInfo: IdxPriceInfo, isPredMkt: boolean): MarginAccount; getMarginAccount(traderAddr: string, symbol: string, idxPriceInfo: IdxPriceInfo, overrides?: Overrides): Promise<MarginAccount>; /** * Get trader state from the blockchain and parse into a human-readable margin account * @param traderAddr Trader address * @param symbol Perpetual symbol * @param symbolToPerpStaticInfo Symbol to perp static info mapping * @param _proxyContract Proxy contract instance * @param _pxInfo index price info * @param overrides Optional overrides for eth_call * @returns A Margin account */ static getMarginAccount(traderAddr: string, symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, _proxyContract: Contract, _pxInfo: IdxPriceInfo, isPredMkt: boolean, overrides?: Overrides): Promise<MarginAccount>; /** * All the orders in the order book for a given symbol that are currently open. * @param {string} symbol Symbol of the form ETH-USD-MATIC. * @example * import { OrderExecutorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk'; * async function main() { * console.log(OrderExecutorTool); * // setup (authentication required, PK is an environment variable with a private key) * const config = PerpetualDataHandler.readSDKConfig("cardona"); * const pk: string = <string>process.env.PK; * let orderTool = new OrderExecutorTool(config, pk); * await orderTool.createProxyInstance(); * // get all open orders * let openOrders = await orderTool.getAllOpenOrders("ETH-USD-MATIC"); * console.log(openOrders); * } * main(); * * @returns Array with all open orders and their IDs. */ getAllOpenOrders(symbol: string, overrides?: Overrides): Promise<[Order[], string[], string[]]>; /** * Total number of limit orders for this symbol, excluding those that have been cancelled/removed. * @param {string} symbol Symbol of the form ETH-USD-MATIC. * @example * import { OrderExecutorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk'; * async function main() { * console.log(OrderExecutorTool); * // setup (authentication required, PK is an environment variable with a private key) * const config = PerpetualDataHandler.readSDKConfig("cardona"); * const pk: string = <string>process.env.PK; * let orderTool = new OrderExecutorTool(config, pk); * await orderTool.createProxyInstance(); * // get all open orders * let numberOfOrders = await orderTool.numberOfOpenOrders("ETH-USD-MATIC"); * console.log(numberOfOrders); * } * main(); * * @returns {number} Number of open orders. */ numberOfOpenOrders(symbol: string, overrides?: Overrides & { rpcURL?: string; }): Promise<number>; /** * Get a list of active conditional orders in the order book. * This a read-only action and does not incur in gas costs. * @param {string} symbol Symbol of the form ETH-USD-MATIC. * @param {number} numElements Maximum number of orders to poll. * @param {string=} startAfter Optional order ID from where to start polling. Defaults to the first order. * @example * import { OrderExecutorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk'; * async function main() { * console.log(OrderExecutorTool); * // setup (authentication required, PK is an environment variable with a private key) * const config = PerpetualDataHandler.readSDKConfig("cardona"); * const pk: string = <string>process.env.PK; * let orderTool = new OrderExecutorTool(config, pk); * await orderTool.createProxyInstance(); * // get all open orders * let activeOrders = await orderTool.pollLimitOrders("ETH-USD-MATIC", 2); * console.log(activeOrders); * } * main(); * * @returns Array of orders and corresponding order IDs */ pollLimitOrders(symbol: string, numElements: number, startAfter?: string | number, overrides?: Overrides & { rpcURL?: string; }): Promise<[Order[], string[], string[]]>; /** * Get trader states from the blockchain and parse into a list of human-readable margin accounts * @param traderAddrs List of trader addresses * @param symbols List of symbols * @param symbolToPerpStaticInfo Symbol to perp static info mapping * @param _multicall Multicall3 contract instance * @param _proxyContract Proxy contract instance * @param _pxInfo List of price info * @param overrides Optional eth_call overrides * @returns List of margin accounts */ static getMarginAccounts(traderAddrs: string[], symbols: string[], symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, _multicall: Multicall3, _proxyContract: Contract, _pxInfo: IdxPriceInfo[], isPredMkt: boolean[], overrides?: Overrides): Promise<MarginAccount[]>; protected static _queryPerpetualPrice(symbol: string, tradeAmount: number, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, _proxyContract: IPerpetualManager, indexPrices: [number, number], conf: bigint, params: bigint, overrides?: Overrides): Promise<number>; /** * * @param symbol perpetual symbol of the form BTC-USDC-USDC * @param symbolToPerpStaticInfo mapping * @param _proxyContract contract instance * @param indexPrices IdxPriceInfo * @param isPredMkt true if prediction market perpetual * @param overrides * @returns mark price */ protected static _queryPerpetualMarkPrice(symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, _proxyContract: IPerpetualManager, indexPrices: IdxPriceInfo, isPredMkt: boolean, overrides?: Overrides): Promise<number>; protected static _queryPerpetualState(symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, _proxyContract: IPerpetualManager, _multicall: Multicall3, indexPrices: IdxPriceInfo, overrides?: Overrides): Promise<PerpetualState>; /** * Calculate long and short exposures from open interest and long/short * @param oi open interest * @param ammPos amm net exposure * @returns long, short exposure */ protected static _oiAndAmmPosToLongShort(oi: bigint, ammPos: bigint): [bigint, bigint]; protected static _parseAMMState(symbol: string, ammState: bigint[], longShort: [bigint, bigint], indexPrices: IdxPriceInfo, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>): PerpetualState; /** * Liquidation price * @param symbol symbol of the form BTC-USD-MATIC * @param traderState BigInt array according to smart contract * @param S2 number, index price S2 * @param symbolToPerpStaticInfo mapping symbol->PerpStaticInfo * @returns liquidation mark-price, corresponding collateral/quote conversion */ protected static _calculateLiquidationPrice(symbol: string, traderState: bigint[], S2: number, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>, isPredMarket: boolean): [number, number, number, number, number]; /** * Finds the perpetual id for a symbol of the form * <base>-<quote>-<collateral>. The function first converts the * token names into bytes4 representation * @param symbol symbol (e.g., BTC-USD-MATC) * @param symbolToPerpStaticInfo map that contains the bytes4-symbol to PerpetualStaticInfo * including id mapping * @returns perpetual id or it fails */ protected static symbolToPerpetualId(symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>): number; protected static symbolToBytes4Symbol(symbol: string): string; private static _getByValue; protected static fromSmartContractOrder(order: SmartContractOrder | IPerpetualOrder.OrderStruct | IPerpetualOrder.OrderStructOutput | IClientOrder.ClientOrderStruct | IClientOrder.ClientOrderStructOutput, symbolToPerpInfoMap: Map<string, PerpetualStaticInfo>): Order; /** * Transform the convenient form of the order into a smart-contract accepted type of order * @param order order type * @param traderAddr address of the trader * @param symbolToPerpetualMap mapping of symbol to perpetual Id * @returns SmartContractOrder */ protected static toSmartContractOrder(order: Order, traderAddr: string, perpStaticInfo: Map<string, PerpetualStaticInfo>): SmartContractOrder; /** * Converts a smart contract order to a client order * @param scOrder Smart contract order * @param parentChildIds Optional parent-child dependency * @returns Client order that can be submitted to the corresponding LOB */ static fromSmartContratOrderToClientOrder(scOrder: SmartContractOrder, parentChildIds?: [string, string]): ClientOrder; /** * Converts a user-friendly order to a client order * @param order Order * @param parentChildIds Optional parent-child dependency * @returns Client order that can be submitted to the corresponding LOB */ static toClientOrder(order: Order, traderAddr: string, perpStaticInfo: Map<string, PerpetualStaticInfo>, parentChildIds?: [string, string]): ClientOrder; /** * Converts an order as stored in the LOB smart contract into a user-friendly order type * @param obOrder Order-book contract order type * @returns User friendly order struct */ static fromClientOrder(obOrder: IClientOrder.ClientOrderStruct | IClientOrder.ClientOrderStructOutput, perpStaticInfo: Map<string, PerpetualStaticInfo>): Order; private static _flagToOrderType; /** * Determine the correct order flags based on the order-properties. * Checks for some misspecifications. * @param order order type * @returns BigNumber flags */ private static _orderTypeToFlag; protected static _getLotSize(symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>): number; protected static _getMinimalPositionSize(symbol: string, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>): number; /** * Get NodeSDKConfig from a chain ID, known config name, or custom file location.. * @param configNameOrfileLocation Name of a known default config, or chain ID, or json-file with required variables for config * @param version Config version number. Defaults to highest version if name or chain ID are not unique * @returns NodeSDKConfig */ static readSDKConfig(configNameOrChainIdOrFileLocation: string | number, version?: number): NodeSDKConfig; /** * Get a NodeSDKConfig from its name * @param name Name of the known config * @param version Version of the config. Defaults to highest available. * @returns NodeSDKConfig */ protected static getConfigByName(name: string, version?: number): NodeSDKConfig | undefined; /** * Get a NodeSDKConfig from a json file. * @param filename Location of the file * @param version Version of the config. Defaults to highest available. * @returns NodeSDKConfig */ protected static getConfigByLocation(filename: string): NodeSDKConfig; /** * Get a NodeSDKConfig from its chain Id * @param chainId Chain Id * @param version Version of the config. Defaults to highest available. * @returns NodeSDKConfig */ protected static getConfigByChainId(chainId: number, version?: number): NodeSDKConfig | undefined; /** * Get available configurations in a Set. * You can use the output to determine the config file that you get * via 'let config = PerpetualDataHandler.readSDKConfig(196);' * @returns set of chain-ids and name separated by ; * @example * import { PerpetualDataHandler } from '@d8x/perpetuals-sdk'; * async function main() { * const configs = PerpetualDataHandler.getAvailableConfigs(); * console.log(configs); * // output of the form: * // Set(2) { '1101; zkevm', `196; xlayer'} * } * main(); */ static getAvailableConfigs(): Set<string>; /** * Get the ABI of a function in a given contract. Undefined if it doesn't exist. * @param contract A contract instance, e.g. this.proxyContract * @param functionName Name of the function whose ABI we want * @returns Function ABI as a single JSON string */ protected static _getABIFromContract(contract: BaseContract, functionName: string): string | undefined; /** * Gets the pool index (starting at 0 in exchangeInfo, not ID!) corresponding to a given symbol. * @param symbol Symbol of the form ETH-USD-MATIC * @returns Pool index */ getPoolStaticInfoIndexFromSymbol(symbol: string): number; /** * * @param symbol Symbol of the form USDC * @returns Address of the corresponding margin token */ getMarginTokenFromSymbol(symbol: string): string | undefined; /** * * @param symbol Symbol of the form ETH-USD-WEETH * @returns Address of the corresponding settlement token */ getSettlementTokenFromSymbol(symbol: string): string | undefined; /** * * @param symbol Symbol of the form USDC * @returns Decimals of the corresponding margin token */ getMarginTokenDecimalsFromSymbol(symbol: string): number | undefined; /** * * @param symbol Symbol of the form ETH-USD-WEETH * @returns Decimals of the corresponding settlement token */ getSettlementTokenDecimalsFromSymbol(symbol: string): number | undefined; /** * Get ABI for LimitOrderBook, Proxy, or Share Pool Token * @param contract name of contract: proxy|lob|sharetoken * @returns ABI for the requested contract */ getABI(contract: string): Interface | undefined; /** * Performs basic validity checks on a given order * @param order Order struct * @param traderAccount Trader account * @param perpStaticInfo Symbol to perpetual info map */ protected static checkOrder(order: Order, perpStaticInfo: Map<string, PerpetualStaticInfo>): void; /** * Converts a client order (with BigNumberish types) to a type-safe order (with number/bigint types) * @param order Client order * @returns Order that can be submitted to the corresponding LOB via ethers v6 or viem */ static fromClientOrderToTypeSafeOrder(order: ClientOrder): TypeSafeOrder; /** * Determines whether a given perpetual represents a prediction market * @param symbol perpetual symbol of the form TRUMP24-USD-USDC * @returns True if this is a prediction market */ isPredictionMarket(symbol: string): boolean; /** * Determines whether a given perpetual represents a low-liquidity market * @param symbol perpetual symbol of the form DIRAC-HONEY-USDC * @returns True if this is a low-liquidity market */ isLowLiquidityMarket(symbol: string): boolean; /** * Determines whether a given perpetual represents a tradfi market * @param symbol perpetual symbol of the form MSTR-HONEY-BUSD * @returns True if this is a tradfi market */ isTradFiMarket(symbol: string): boolean; /** * Returns day trading times for tradfi markets * @param symbol perpetual symbol of the form MSTR-HONEY-BUSD * @returns open time in seconds within day, close time in seconds within day */ getMarketDayTradingOpenCloseSec(symbol: string): { openSec: number; closeSec: number; }; getMarketDayTradingNextEvent(symbol: string): { event: string; ts: number; tsStr: string; }; /** * Determines whether a given perpetual represents a tradfi market * which has open/close times * @param staticInfo Perpetual static info * @returns True if perp has tradfi market flag set */ static isTradFiMarketStatic(staticInfo: PerpetualStaticInfo): boolean; /** * Determines whether a given perpetual represents a prediction market * @param staticInfo Perpetual static info * @returns True if this is a prediction market */ static isPredictionMarketStatic(staticInfo: PerpetualStaticInfo): boolean; /** * getInitialMarginRate * @param symbol perpetual symbol MSTR-USD-BUSD * @returns initial margin rate */ getInitialMarginRate(symbol: string): number; /** * getMaintenanceMarginRate * @param symbol perpetual symbol MSTR-USD-BUSD * @returns maintenance margin rate */ getMaintenanceMarginRate(symbol: string): number; /** * Get initial margin rate from static data considering open/close of tradfi markets * @param staticInfo static info * @returns initial margin rate in decimals */ static getInitialMarginRate(staticInfo: PerpetualStaticInfo): number; /** * Get maintenance margin rate from static data considering open/close of tradfi markets * @param staticInfo static info * @returns maintenance margin rate in decimals */ static getMaintenanceMarginRate(staticInfo: PerpetualStaticInfo): number; /** * Determine whether the market is in day trading, given the parameter fAMMTargetDD * @param fAMMTargetDD bigint that encodes market day trading times * @returns true if currently the market is in day trading status */ static isMarketDayTime(fAMMTargetDD: bigint): boolean; static decodeOpenCloseSeconds(packed: bigint): { openSec: number; closeSec: number; }; }