@velocity-exchange/sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +1 -0
- package/.yarn/install-state.gz +0 -0
- package/README.md +275 -0
- package/VERSION +1 -0
- package/build-browser.js +58 -0
- package/bun.lock +1885 -0
- package/esbuild-shims.js +12 -0
- package/lib/browser/accounts/basicUserAccountSubscriber.d.ts +27 -0
- package/lib/browser/accounts/basicUserAccountSubscriber.js +38 -0
- package/lib/browser/accounts/basicUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/browser/accounts/basicUserStatsAccountSubscriber.js +38 -0
- package/lib/browser/accounts/bulkAccountLoader.d.ts +37 -0
- package/lib/browser/accounts/bulkAccountLoader.js +222 -0
- package/lib/browser/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/browser/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/browser/accounts/bulkUserSubscription.d.ts +7 -0
- package/lib/browser/accounts/bulkUserSubscription.js +21 -0
- package/lib/browser/accounts/customizedCadenceBulkAccountLoader.d.ts +44 -0
- package/lib/browser/accounts/customizedCadenceBulkAccountLoader.js +152 -0
- package/lib/browser/accounts/fetch.d.ts +17 -0
- package/lib/browser/accounts/fetch.js +60 -0
- package/lib/browser/accounts/grpcAccountSubscriber.d.ts +17 -0
- package/lib/browser/accounts/grpcAccountSubscriber.js +162 -0
- package/lib/browser/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +10 -0
- package/lib/browser/accounts/grpcInsuranceFundStakeAccountSubscriber.js +31 -0
- package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +37 -0
- package/lib/browser/accounts/grpcMultiAccountSubscriber.js +378 -0
- package/lib/browser/accounts/grpcMultiUserAccountSubscriber.d.ts +25 -0
- package/lib/browser/accounts/grpcMultiUserAccountSubscriber.js +203 -0
- package/lib/browser/accounts/grpcProgramAccountSubscriber.d.ts +18 -0
- package/lib/browser/accounts/grpcProgramAccountSubscriber.js +179 -0
- package/lib/browser/accounts/grpcUserAccountSubscriber.d.ts +10 -0
- package/lib/browser/accounts/grpcUserAccountSubscriber.js +28 -0
- package/lib/browser/accounts/grpcUserStatsAccountSubscriber.d.ts +10 -0
- package/lib/browser/accounts/grpcUserStatsAccountSubscriber.js +28 -0
- package/lib/browser/accounts/grpcVelocityClientAccountSubscriber.d.ts +16 -0
- package/lib/browser/accounts/grpcVelocityClientAccountSubscriber.js +101 -0
- package/lib/browser/accounts/grpcVelocityClientAccountSubscriberV2.d.ts +69 -0
- package/lib/browser/accounts/grpcVelocityClientAccountSubscriberV2.js +457 -0
- package/lib/browser/accounts/laserProgramAccountSubscriber.d.ts +23 -0
- package/lib/browser/accounts/laserProgramAccountSubscriber.js +162 -0
- package/lib/browser/accounts/oneShotUserAccountSubscriber.d.ts +18 -0
- package/lib/browser/accounts/oneShotUserAccountSubscriber.js +48 -0
- package/lib/browser/accounts/oneShotUserStatsAccountSubscriber.d.ts +18 -0
- package/lib/browser/accounts/oneShotUserStatsAccountSubscriber.js +48 -0
- package/lib/browser/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +29 -0
- package/lib/browser/accounts/pollingInsuranceFundStakeAccountSubscriber.js +110 -0
- package/lib/browser/accounts/pollingOracleAccountSubscriber.d.ts +27 -0
- package/lib/browser/accounts/pollingOracleAccountSubscriber.js +78 -0
- package/lib/browser/accounts/pollingTokenAccountSubscriber.d.ts +26 -0
- package/lib/browser/accounts/pollingTokenAccountSubscriber.js +78 -0
- package/lib/browser/accounts/pollingUserAccountSubscriber.d.ts +29 -0
- package/lib/browser/accounts/pollingUserAccountSubscriber.js +102 -0
- package/lib/browser/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/browser/accounts/pollingUserStatsAccountSubscriber.js +94 -0
- package/lib/browser/accounts/pollingVelocityClientAccountSubscriber.d.ts +73 -0
- package/lib/browser/accounts/pollingVelocityClientAccountSubscriber.js +420 -0
- package/lib/browser/accounts/testBulkAccountLoader.d.ts +4 -0
- package/lib/browser/accounts/testBulkAccountLoader.js +43 -0
- package/lib/browser/accounts/types.d.ts +205 -0
- package/lib/browser/accounts/types.js +16 -0
- package/lib/browser/accounts/utils.d.ts +8 -0
- package/lib/browser/accounts/utils.js +49 -0
- package/lib/browser/accounts/webSocketAccountSubscriber.d.ts +29 -0
- package/lib/browser/accounts/webSocketAccountSubscriber.js +170 -0
- package/lib/browser/accounts/webSocketAccountSubscriberV2.d.ts +109 -0
- package/lib/browser/accounts/webSocketAccountSubscriberV2.js +395 -0
- package/lib/browser/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +23 -0
- package/lib/browser/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +67 -0
- package/lib/browser/accounts/webSocketProgramAccountSubscriber.d.ts +31 -0
- package/lib/browser/accounts/webSocketProgramAccountSubscriber.js +120 -0
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.d.ts +145 -0
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.js +744 -0
- package/lib/browser/accounts/webSocketProgramAccountsSubscriberV2.d.ts +145 -0
- package/lib/browser/accounts/webSocketProgramAccountsSubscriberV2.js +744 -0
- package/lib/browser/accounts/webSocketUserAccountSubscriber.d.ts +23 -0
- package/lib/browser/accounts/webSocketUserAccountSubscriber.js +61 -0
- package/lib/browser/accounts/webSocketUserStatsAccountSubsriber.d.ts +22 -0
- package/lib/browser/accounts/webSocketUserStatsAccountSubsriber.js +52 -0
- package/lib/browser/accounts/webSocketVelocityClientAccountSubscriber.d.ts +77 -0
- package/lib/browser/accounts/webSocketVelocityClientAccountSubscriber.js +400 -0
- package/lib/browser/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts +91 -0
- package/lib/browser/accounts/webSocketVelocityClientAccountSubscriberV2.js +446 -0
- package/lib/browser/accounts/websocketProgramUserAccountSubscriber.d.ts +22 -0
- package/lib/browser/accounts/websocketProgramUserAccountSubscriber.js +54 -0
- package/lib/browser/addresses/marketAddresses.d.ts +2 -0
- package/lib/browser/addresses/marketAddresses.js +15 -0
- package/lib/browser/addresses/pda.d.ts +47 -0
- package/lib/browser/addresses/pda.js +263 -0
- package/lib/browser/adminClient.d.ts +402 -0
- package/lib/browser/adminClient.js +2798 -0
- package/lib/browser/assert/assert.d.ts +1 -0
- package/lib/browser/assert/assert.js +9 -0
- package/lib/browser/auctionSubscriber/auctionSubscriber.d.ts +14 -0
- package/lib/browser/auctionSubscriber/auctionSubscriber.js +32 -0
- package/lib/browser/auctionSubscriber/auctionSubscriberGrpc.d.ts +15 -0
- package/lib/browser/auctionSubscriber/auctionSubscriberGrpc.js +32 -0
- package/lib/browser/auctionSubscriber/index.d.ts +3 -0
- package/lib/browser/auctionSubscriber/index.js +19 -0
- package/lib/browser/auctionSubscriber/types.d.ts +14 -0
- package/lib/browser/auctionSubscriber/types.js +2 -0
- package/lib/browser/bankrun/bankrunConnection.d.ts +76 -0
- package/lib/browser/bankrun/bankrunConnection.js +348 -0
- package/lib/browser/blockhashSubscriber/BlockhashSubscriber.d.ts +27 -0
- package/lib/browser/blockhashSubscriber/BlockhashSubscriber.js +89 -0
- package/lib/browser/blockhashSubscriber/index.d.ts +1 -0
- package/lib/browser/blockhashSubscriber/index.js +17 -0
- package/lib/browser/blockhashSubscriber/types.d.ts +7 -0
- package/lib/browser/blockhashSubscriber/types.js +2 -0
- package/lib/browser/clock/clockSubscriber.d.ts +31 -0
- package/lib/browser/clock/clockSubscriber.js +80 -0
- package/lib/browser/config.d.ts +75 -0
- package/lib/browser/config.js +164 -0
- package/lib/browser/constants/index.d.ts +10 -0
- package/lib/browser/constants/index.js +26 -0
- package/lib/browser/constants/insuranceFund.d.ts +5 -0
- package/lib/browser/constants/insuranceFund.js +9 -0
- package/lib/browser/constants/numericConstants.d.ts +73 -0
- package/lib/browser/constants/numericConstants.js +79 -0
- package/lib/browser/constants/perpMarkets.d.ts +21 -0
- package/lib/browser/constants/perpMarkets.js +971 -0
- package/lib/browser/constants/spotMarkets.d.ts +24 -0
- package/lib/browser/constants/spotMarkets.js +797 -0
- package/lib/browser/constants/txConstants.d.ts +1 -0
- package/lib/browser/constants/txConstants.js +4 -0
- package/lib/browser/constituentMap/constituentMap.d.ts +66 -0
- package/lib/browser/constituentMap/constituentMap.js +177 -0
- package/lib/browser/constituentMap/pollingConstituentAccountSubscriber.d.ts +24 -0
- package/lib/browser/constituentMap/pollingConstituentAccountSubscriber.js +60 -0
- package/lib/browser/constituentMap/webSocketConstituentAccountSubscriber.d.ts +24 -0
- package/lib/browser/constituentMap/webSocketConstituentAccountSubscriber.js +58 -0
- package/lib/browser/core/VelocityCore.d.ts +226 -0
- package/lib/browser/core/VelocityCore.js +138 -0
- package/lib/browser/core/index.d.ts +12 -0
- package/lib/browser/core/index.js +28 -0
- package/lib/browser/core/instructions/deposit.d.ts +19 -0
- package/lib/browser/core/instructions/deposit.js +19 -0
- package/lib/browser/core/instructions/fill.d.ts +13 -0
- package/lib/browser/core/instructions/fill.js +17 -0
- package/lib/browser/core/instructions/funding.d.ts +9 -0
- package/lib/browser/core/instructions/funding.js +13 -0
- package/lib/browser/core/instructions/liquidation.d.ts +15 -0
- package/lib/browser/core/instructions/liquidation.js +17 -0
- package/lib/browser/core/instructions/orders.d.ts +22 -0
- package/lib/browser/core/instructions/orders.js +27 -0
- package/lib/browser/core/instructions/perpOrders.d.ts +78 -0
- package/lib/browser/core/instructions/perpOrders.js +99 -0
- package/lib/browser/core/instructions/settlement.d.ts +11 -0
- package/lib/browser/core/instructions/settlement.js +15 -0
- package/lib/browser/core/instructions/trigger.d.ts +11 -0
- package/lib/browser/core/instructions/trigger.js +15 -0
- package/lib/browser/core/instructions/withdraw.d.ts +20 -0
- package/lib/browser/core/instructions/withdraw.js +20 -0
- package/lib/browser/core/remainingAccounts.d.ts +27 -0
- package/lib/browser/core/remainingAccounts.js +122 -0
- package/lib/browser/core/signedMsg.d.ts +17 -0
- package/lib/browser/core/signedMsg.js +39 -0
- package/lib/browser/decode/customCoder.d.ts +44 -0
- package/lib/browser/decode/customCoder.js +64 -0
- package/lib/browser/decode/user.d.ts +4 -0
- package/lib/browser/decode/user.js +337 -0
- package/lib/browser/dlob/DLOB.d.ts +253 -0
- package/lib/browser/dlob/DLOB.js +1137 -0
- package/lib/browser/dlob/DLOBNode.d.ts +70 -0
- package/lib/browser/dlob/DLOBNode.js +103 -0
- package/lib/browser/dlob/DLOBSubscriber.d.ts +57 -0
- package/lib/browser/dlob/DLOBSubscriber.js +143 -0
- package/lib/browser/dlob/NodeList.d.ts +27 -0
- package/lib/browser/dlob/NodeList.js +126 -0
- package/lib/browser/dlob/orderBookLevels.d.ts +77 -0
- package/lib/browser/dlob/orderBookLevels.js +404 -0
- package/lib/browser/dlob/types.d.ts +18 -0
- package/lib/browser/dlob/types.js +2 -0
- package/lib/browser/events/eventList.d.ts +22 -0
- package/lib/browser/events/eventList.js +80 -0
- package/lib/browser/events/eventSubscriber.d.ts +55 -0
- package/lib/browser/events/eventSubscriber.js +229 -0
- package/lib/browser/events/eventsServerLogProvider.d.ts +21 -0
- package/lib/browser/events/eventsServerLogProvider.js +121 -0
- package/lib/browser/events/fetchLogs.d.ts +25 -0
- package/lib/browser/events/fetchLogs.js +99 -0
- package/lib/browser/events/parse.d.ts +8 -0
- package/lib/browser/events/parse.js +199 -0
- package/lib/browser/events/pollingLogProvider.d.ts +17 -0
- package/lib/browser/events/pollingLogProvider.js +58 -0
- package/lib/browser/events/sort.d.ts +2 -0
- package/lib/browser/events/sort.js +24 -0
- package/lib/browser/events/txEventCache.d.ts +24 -0
- package/lib/browser/events/txEventCache.js +71 -0
- package/lib/browser/events/types.d.ts +104 -0
- package/lib/browser/events/types.js +36 -0
- package/lib/browser/events/webSocketLogProvider.d.ts +24 -0
- package/lib/browser/events/webSocketLogProvider.js +96 -0
- package/lib/browser/factory/bigNum.d.ts +122 -0
- package/lib/browser/factory/bigNum.js +500 -0
- package/lib/browser/factory/oracleClient.d.ts +5 -0
- package/lib/browser/factory/oracleClient.js +53 -0
- package/lib/browser/idl/drift.d.ts +23894 -0
- package/lib/browser/idl/drift.js +2 -0
- package/lib/browser/idl/drift.json +18698 -0
- package/lib/browser/idl/pyth.d.ts +97 -0
- package/lib/browser/idl/pyth.js +2 -0
- package/lib/browser/idl/token_faucet.d.ts +197 -0
- package/lib/browser/idl/token_faucet.js +2 -0
- package/lib/browser/idl/token_faucet.json +229 -0
- package/lib/browser/index.d.ts +144 -0
- package/lib/browser/index.js +175 -0
- package/lib/browser/indicative-quotes/indicativeQuotesSender.d.ts +35 -0
- package/lib/browser/indicative-quotes/indicativeQuotesSender.js +192 -0
- package/lib/browser/isomorphic/anchor.browser.d.ts +24 -0
- package/lib/browser/isomorphic/anchor.browser.js +60 -0
- package/lib/browser/isomorphic/anchor.d.ts +24 -0
- package/lib/browser/isomorphic/anchor.js +60 -0
- package/lib/browser/isomorphic/anchor29.browser.d.ts +12 -0
- package/lib/browser/isomorphic/anchor29.browser.js +48 -0
- package/lib/browser/isomorphic/anchor29.d.ts +12 -0
- package/lib/browser/isomorphic/anchor29.js +48 -0
- package/lib/browser/isomorphic/grpc.browser.d.ts +1 -0
- package/lib/browser/isomorphic/grpc.browser.js +8 -0
- package/lib/browser/isomorphic/grpc.d.ts +1 -0
- package/lib/browser/isomorphic/grpc.js +8 -0
- package/lib/browser/jupiter/jupiterClient.d.ts +291 -0
- package/lib/browser/jupiter/jupiterClient.js +164 -0
- package/lib/browser/keypair.d.ts +2 -0
- package/lib/browser/keypair.js +28 -0
- package/lib/browser/marginCalculation.d.ts +67 -0
- package/lib/browser/marginCalculation.js +176 -0
- package/lib/browser/marinade/index.d.ts +12 -0
- package/lib/browser/marinade/index.js +36 -0
- package/lib/browser/marinade/types.d.ts +1963 -0
- package/lib/browser/marinade/types.js +1965 -0
- package/lib/browser/math/amm.d.ts +98 -0
- package/lib/browser/math/amm.js +671 -0
- package/lib/browser/math/auction.d.ts +65 -0
- package/lib/browser/math/auction.js +261 -0
- package/lib/browser/math/bankruptcy.d.ts +2 -0
- package/lib/browser/math/bankruptcy.js +32 -0
- package/lib/browser/math/builder.d.ts +5 -0
- package/lib/browser/math/builder.js +22 -0
- package/lib/browser/math/conversion.d.ts +4 -0
- package/lib/browser/math/conversion.js +21 -0
- package/lib/browser/math/exchangeStatus.d.ts +8 -0
- package/lib/browser/math/exchangeStatus.js +85 -0
- package/lib/browser/math/funding.d.ts +44 -0
- package/lib/browser/math/funding.js +260 -0
- package/lib/browser/math/insurance.d.ts +8 -0
- package/lib/browser/math/insurance.js +74 -0
- package/lib/browser/math/liquidation.d.ts +7 -0
- package/lib/browser/math/liquidation.js +134 -0
- package/lib/browser/math/margin.d.ts +45 -0
- package/lib/browser/math/margin.js +205 -0
- package/lib/browser/math/market.d.ts +50 -0
- package/lib/browser/math/market.js +234 -0
- package/lib/browser/math/oracles.d.ts +19 -0
- package/lib/browser/math/oracles.js +215 -0
- package/lib/browser/math/orders.d.ts +36 -0
- package/lib/browser/math/orders.js +294 -0
- package/lib/browser/math/position.d.ts +71 -0
- package/lib/browser/math/position.js +232 -0
- package/lib/browser/math/repeg.d.ts +22 -0
- package/lib/browser/math/repeg.js +164 -0
- package/lib/browser/math/spotBalance.d.ts +85 -0
- package/lib/browser/math/spotBalance.js +438 -0
- package/lib/browser/math/spotMarket.d.ts +11 -0
- package/lib/browser/math/spotMarket.js +49 -0
- package/lib/browser/math/spotPosition.d.ts +19 -0
- package/lib/browser/math/spotPosition.js +79 -0
- package/lib/browser/math/state.d.ts +8 -0
- package/lib/browser/math/state.js +44 -0
- package/lib/browser/math/superStake.d.ts +168 -0
- package/lib/browser/math/superStake.js +308 -0
- package/lib/browser/math/tiers.d.ts +4 -0
- package/lib/browser/math/tiers.js +52 -0
- package/lib/browser/math/trade.d.ts +93 -0
- package/lib/browser/math/trade.js +503 -0
- package/lib/browser/math/utils.d.ts +23 -0
- package/lib/browser/math/utils.js +113 -0
- package/lib/browser/memcmp.d.ts +18 -0
- package/lib/browser/memcmp.js +162 -0
- package/lib/browser/oracles/oracleClientCache.d.ts +9 -0
- package/lib/browser/oracles/oracleClientCache.js +19 -0
- package/lib/browser/oracles/oracleId.d.ts +9 -0
- package/lib/browser/oracles/oracleId.js +89 -0
- package/lib/browser/oracles/prelaunchOracleClient.d.ts +12 -0
- package/lib/browser/oracles/prelaunchOracleClient.js +24 -0
- package/lib/browser/oracles/pythClient.d.ts +14 -0
- package/lib/browser/oracles/pythClient.js +51 -0
- package/lib/browser/oracles/pythLazerClient.d.ts +16 -0
- package/lib/browser/oracles/pythLazerClient.js +61 -0
- package/lib/browser/oracles/quoteAssetOracleClient.d.ts +10 -0
- package/lib/browser/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/browser/oracles/strictOraclePrice.d.ts +9 -0
- package/lib/browser/oracles/strictOraclePrice.js +17 -0
- package/lib/browser/oracles/types.d.ts +33 -0
- package/lib/browser/oracles/types.js +2 -0
- package/lib/browser/oracles/utils.d.ts +4 -0
- package/lib/browser/oracles/utils.js +8 -0
- package/lib/browser/orderParams.d.ts +29 -0
- package/lib/browser/orderParams.js +44 -0
- package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +45 -0
- package/lib/browser/orderSubscriber/OrderSubscriber.js +193 -0
- package/lib/browser/orderSubscriber/PollingSubscription.d.ts +12 -0
- package/lib/browser/orderSubscriber/PollingSubscription.js +23 -0
- package/lib/browser/orderSubscriber/WebsocketSubscription.d.ts +23 -0
- package/lib/browser/orderSubscriber/WebsocketSubscription.js +67 -0
- package/lib/browser/orderSubscriber/grpcSubscription.d.ts +22 -0
- package/lib/browser/orderSubscriber/grpcSubscription.js +75 -0
- package/lib/browser/orderSubscriber/index.d.ts +7 -0
- package/lib/browser/orderSubscriber/index.js +23 -0
- package/lib/browser/orderSubscriber/types.d.ts +35 -0
- package/lib/browser/orderSubscriber/types.js +2 -0
- package/lib/browser/priorityFee/averageOverSlotsStrategy.d.ts +5 -0
- package/lib/browser/priorityFee/averageOverSlotsStrategy.js +16 -0
- package/lib/browser/priorityFee/averageStrategy.d.ts +5 -0
- package/lib/browser/priorityFee/averageStrategy.js +11 -0
- package/lib/browser/priorityFee/ewmaStrategy.d.ts +11 -0
- package/lib/browser/priorityFee/ewmaStrategy.js +33 -0
- package/lib/browser/priorityFee/heliusPriorityFeeMethod.d.ts +20 -0
- package/lib/browser/priorityFee/heliusPriorityFeeMethod.js +46 -0
- package/lib/browser/priorityFee/index.d.ts +16 -0
- package/lib/browser/priorityFee/index.js +32 -0
- package/lib/browser/priorityFee/maxOverSlotsStrategy.d.ts +5 -0
- package/lib/browser/priorityFee/maxOverSlotsStrategy.js +17 -0
- package/lib/browser/priorityFee/maxStrategy.d.ts +7 -0
- package/lib/browser/priorityFee/maxStrategy.js +9 -0
- package/lib/browser/priorityFee/priorityFeeSubscriber.d.ts +48 -0
- package/lib/browser/priorityFee/priorityFeeSubscriber.js +193 -0
- package/lib/browser/priorityFee/priorityFeeSubscriberMap.d.ts +50 -0
- package/lib/browser/priorityFee/priorityFeeSubscriberMap.js +96 -0
- package/lib/browser/priorityFee/solanaPriorityFeeMethod.d.ts +6 -0
- package/lib/browser/priorityFee/solanaPriorityFeeMethod.js +21 -0
- package/lib/browser/priorityFee/types.d.ts +35 -0
- package/lib/browser/priorityFee/types.js +10 -0
- package/lib/browser/priorityFee/velocityPriorityFeeMethod.d.ts +21 -0
- package/lib/browser/priorityFee/velocityPriorityFeeMethod.js +28 -0
- package/lib/browser/pyth/constants.d.ts +3 -0
- package/lib/browser/pyth/constants.js +6 -0
- package/lib/browser/pyth/index.d.ts +4 -0
- package/lib/browser/pyth/index.js +12 -0
- package/lib/browser/pyth/pythLazerSubscriber.d.ts +91 -0
- package/lib/browser/pyth/pythLazerSubscriber.js +276 -0
- package/lib/browser/pyth/types.d.ts +2226 -0
- package/lib/browser/pyth/types.js +2224 -0
- package/lib/browser/pyth/utils.d.ts +2 -0
- package/lib/browser/pyth/utils.js +10 -0
- package/lib/browser/slot/SlotSubscriber.d.ts +27 -0
- package/lib/browser/slot/SlotSubscriber.js +76 -0
- package/lib/browser/slot/SlothashSubscriber.d.ts +25 -0
- package/lib/browser/slot/SlothashSubscriber.js +88 -0
- package/lib/browser/swap/UnifiedSwapClient.d.ts +120 -0
- package/lib/browser/swap/UnifiedSwapClient.js +179 -0
- package/lib/browser/swift/grpcSignedMsgUserAccountSubscriber.d.ts +22 -0
- package/lib/browser/swift/grpcSignedMsgUserAccountSubscriber.js +57 -0
- package/lib/browser/swift/index.d.ts +10 -0
- package/lib/browser/swift/index.js +26 -0
- package/lib/browser/swift/signedMsgUserAccountSubscriber.d.ts +42 -0
- package/lib/browser/swift/signedMsgUserAccountSubscriber.js +118 -0
- package/lib/browser/swift/swiftOrderSubscriber.d.ts +63 -0
- package/lib/browser/swift/swiftOrderSubscriber.js +187 -0
- package/lib/browser/testClient.d.ts +8 -0
- package/lib/browser/testClient.js +24 -0
- package/lib/browser/titan/titanClient.d.ts +90 -0
- package/lib/browser/titan/titanClient.js +227 -0
- package/lib/browser/token/index.d.ts +5 -0
- package/lib/browser/token/index.js +15 -0
- package/lib/browser/tokenFaucet.d.ts +41 -0
- package/lib/browser/tokenFaucet.js +188 -0
- package/lib/browser/tx/baseTxSender.d.ts +59 -0
- package/lib/browser/tx/baseTxSender.js +292 -0
- package/lib/browser/tx/blockhashFetcher/baseBlockhashFetcher.d.ts +8 -0
- package/lib/browser/tx/blockhashFetcher/baseBlockhashFetcher.js +13 -0
- package/lib/browser/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts +28 -0
- package/lib/browser/tx/blockhashFetcher/cachedBlockhashFetcher.js +73 -0
- package/lib/browser/tx/blockhashFetcher/types.d.ts +4 -0
- package/lib/browser/tx/blockhashFetcher/types.js +2 -0
- package/lib/browser/tx/fastSingleTxSender.d.ts +41 -0
- package/lib/browser/tx/fastSingleTxSender.js +86 -0
- package/lib/browser/tx/forwardOnlyTxSender.d.ts +37 -0
- package/lib/browser/tx/forwardOnlyTxSender.js +92 -0
- package/lib/browser/tx/priorityFeeCalculator.d.ts +44 -0
- package/lib/browser/tx/priorityFeeCalculator.js +85 -0
- package/lib/browser/tx/reportTransactionError.d.ts +20 -0
- package/lib/browser/tx/reportTransactionError.js +103 -0
- package/lib/browser/tx/retryTxSender.d.ts +37 -0
- package/lib/browser/tx/retryTxSender.js +86 -0
- package/lib/browser/tx/txHandler.d.ts +173 -0
- package/lib/browser/tx/txHandler.js +522 -0
- package/lib/browser/tx/txParamProcessor.d.ts +26 -0
- package/lib/browser/tx/txParamProcessor.js +92 -0
- package/lib/browser/tx/types.d.ts +29 -0
- package/lib/browser/tx/types.js +20 -0
- package/lib/browser/tx/utils.d.ts +6 -0
- package/lib/browser/tx/utils.js +78 -0
- package/lib/browser/tx/whileValidTxSender.d.ts +45 -0
- package/lib/browser/tx/whileValidTxSender.js +168 -0
- package/lib/browser/types.d.ts +1747 -0
- package/lib/browser/types.js +427 -0
- package/lib/browser/user.d.ts +446 -0
- package/lib/browser/user.js +2372 -0
- package/lib/browser/userConfig.d.ts +31 -0
- package/lib/browser/userConfig.js +2 -0
- package/lib/browser/userMap/PollingSubscription.d.ts +15 -0
- package/lib/browser/userMap/PollingSubscription.js +30 -0
- package/lib/browser/userMap/WebsocketSubscription.d.ts +27 -0
- package/lib/browser/userMap/WebsocketSubscription.js +45 -0
- package/lib/browser/userMap/grpcSubscription.d.ts +27 -0
- package/lib/browser/userMap/grpcSubscription.js +44 -0
- package/lib/browser/userMap/referrerMap.d.ts +45 -0
- package/lib/browser/userMap/referrerMap.js +184 -0
- package/lib/browser/userMap/revenueShareEscrowMap.d.ts +66 -0
- package/lib/browser/userMap/revenueShareEscrowMap.js +210 -0
- package/lib/browser/userMap/userMap.d.ts +114 -0
- package/lib/browser/userMap/userMap.js +486 -0
- package/lib/browser/userMap/userMapConfig.d.ts +40 -0
- package/lib/browser/userMap/userMapConfig.js +2 -0
- package/lib/browser/userMap/userStatsMap.d.ts +66 -0
- package/lib/browser/userMap/userStatsMap.js +266 -0
- package/lib/browser/userName.d.ts +5 -0
- package/lib/browser/userName.js +21 -0
- package/lib/browser/userStats.d.ts +24 -0
- package/lib/browser/userStats.js +70 -0
- package/lib/browser/userStatsConfig.d.ts +26 -0
- package/lib/browser/userStatsConfig.js +2 -0
- package/lib/browser/util/TransactionConfirmationManager.d.ts +16 -0
- package/lib/browser/util/TransactionConfirmationManager.js +174 -0
- package/lib/browser/util/chainClock.d.ts +17 -0
- package/lib/browser/util/chainClock.js +29 -0
- package/lib/browser/util/computeUnits.d.ts +8 -0
- package/lib/browser/util/computeUnits.js +48 -0
- package/lib/browser/util/digest.d.ts +5 -0
- package/lib/browser/util/digest.js +19 -0
- package/lib/browser/util/ed25519Utils.d.ts +10 -0
- package/lib/browser/util/ed25519Utils.js +80 -0
- package/lib/browser/util/promiseTimeout.d.ts +1 -0
- package/lib/browser/util/promiseTimeout.js +14 -0
- package/lib/browser/util/tps.d.ts +2 -0
- package/lib/browser/util/tps.js +16 -0
- package/lib/browser/velocityClient.d.ts +1230 -0
- package/lib/browser/velocityClient.js +5778 -0
- package/lib/browser/velocityClientConfig.d.ts +84 -0
- package/lib/browser/velocityClientConfig.js +2 -0
- package/lib/browser/wallet.d.ts +16 -0
- package/lib/browser/wallet.js +46 -0
- package/lib/node/accounts/basicUserAccountSubscriber.d.ts +28 -0
- package/lib/node/accounts/basicUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/basicUserAccountSubscriber.js +38 -0
- package/lib/node/accounts/basicUserStatsAccountSubscriber.d.ts +28 -0
- package/lib/node/accounts/basicUserStatsAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/basicUserStatsAccountSubscriber.js +38 -0
- package/lib/node/accounts/bulkAccountLoader.d.ts +38 -0
- package/lib/node/accounts/bulkAccountLoader.d.ts.map +1 -0
- package/lib/node/accounts/bulkAccountLoader.js +222 -0
- package/lib/node/accounts/bulkUserStatsSubscription.d.ts +8 -0
- package/lib/node/accounts/bulkUserStatsSubscription.d.ts.map +1 -0
- package/lib/node/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/node/accounts/bulkUserSubscription.d.ts +8 -0
- package/lib/node/accounts/bulkUserSubscription.d.ts.map +1 -0
- package/lib/node/accounts/bulkUserSubscription.js +21 -0
- package/lib/node/accounts/customizedCadenceBulkAccountLoader.d.ts +45 -0
- package/lib/node/accounts/customizedCadenceBulkAccountLoader.d.ts.map +1 -0
- package/lib/node/accounts/customizedCadenceBulkAccountLoader.js +152 -0
- package/lib/node/accounts/fetch.d.ts +18 -0
- package/lib/node/accounts/fetch.d.ts.map +1 -0
- package/lib/node/accounts/fetch.js +60 -0
- package/lib/node/accounts/grpcAccountSubscriber.d.ts +18 -0
- package/lib/node/accounts/grpcAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcAccountSubscriber.js +162 -0
- package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +11 -0
- package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.js +31 -0
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +38 -0
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcMultiAccountSubscriber.js +378 -0
- package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts +26 -0
- package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcMultiUserAccountSubscriber.js +203 -0
- package/lib/node/accounts/grpcProgramAccountSubscriber.d.ts +19 -0
- package/lib/node/accounts/grpcProgramAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcProgramAccountSubscriber.js +179 -0
- package/lib/node/accounts/grpcUserAccountSubscriber.d.ts +11 -0
- package/lib/node/accounts/grpcUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcUserAccountSubscriber.js +28 -0
- package/lib/node/accounts/grpcUserStatsAccountSubscriber.d.ts +11 -0
- package/lib/node/accounts/grpcUserStatsAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcUserStatsAccountSubscriber.js +28 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriber.d.ts +17 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriber.js +101 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.d.ts +70 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.js +457 -0
- package/lib/node/accounts/laserProgramAccountSubscriber.d.ts +24 -0
- package/lib/node/accounts/laserProgramAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/laserProgramAccountSubscriber.js +162 -0
- package/lib/node/accounts/oneShotUserAccountSubscriber.d.ts +19 -0
- package/lib/node/accounts/oneShotUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/oneShotUserAccountSubscriber.js +48 -0
- package/lib/node/accounts/oneShotUserStatsAccountSubscriber.d.ts +19 -0
- package/lib/node/accounts/oneShotUserStatsAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/oneShotUserStatsAccountSubscriber.js +48 -0
- package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +30 -0
- package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.js +110 -0
- package/lib/node/accounts/pollingOracleAccountSubscriber.d.ts +28 -0
- package/lib/node/accounts/pollingOracleAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingOracleAccountSubscriber.js +78 -0
- package/lib/node/accounts/pollingTokenAccountSubscriber.d.ts +27 -0
- package/lib/node/accounts/pollingTokenAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingTokenAccountSubscriber.js +78 -0
- package/lib/node/accounts/pollingUserAccountSubscriber.d.ts +30 -0
- package/lib/node/accounts/pollingUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingUserAccountSubscriber.js +102 -0
- package/lib/node/accounts/pollingUserStatsAccountSubscriber.d.ts +28 -0
- package/lib/node/accounts/pollingUserStatsAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingUserStatsAccountSubscriber.js +94 -0
- package/lib/node/accounts/pollingVelocityClientAccountSubscriber.d.ts +74 -0
- package/lib/node/accounts/pollingVelocityClientAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/pollingVelocityClientAccountSubscriber.js +420 -0
- package/lib/node/accounts/testBulkAccountLoader.d.ts +5 -0
- package/lib/node/accounts/testBulkAccountLoader.d.ts.map +1 -0
- package/lib/node/accounts/testBulkAccountLoader.js +43 -0
- package/lib/node/accounts/types.d.ts +206 -0
- package/lib/node/accounts/types.d.ts.map +1 -0
- package/lib/node/accounts/types.js +16 -0
- package/lib/node/accounts/utils.d.ts +9 -0
- package/lib/node/accounts/utils.d.ts.map +1 -0
- package/lib/node/accounts/utils.js +49 -0
- package/lib/node/accounts/webSocketAccountSubscriber.d.ts +30 -0
- package/lib/node/accounts/webSocketAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketAccountSubscriber.js +170 -0
- package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts +110 -0
- package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/webSocketAccountSubscriberV2.js +395 -0
- package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +24 -0
- package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +67 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriber.d.ts +32 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriber.js +120 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts +146 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.js +744 -0
- package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts +146 -0
- package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.js +744 -0
- package/lib/node/accounts/webSocketUserAccountSubscriber.d.ts +24 -0
- package/lib/node/accounts/webSocketUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketUserAccountSubscriber.js +61 -0
- package/lib/node/accounts/webSocketUserStatsAccountSubsriber.d.ts +23 -0
- package/lib/node/accounts/webSocketUserStatsAccountSubsriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketUserStatsAccountSubsriber.js +52 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.d.ts +78 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.js +400 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts +92 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.js +446 -0
- package/lib/node/accounts/websocketProgramUserAccountSubscriber.d.ts +23 -0
- package/lib/node/accounts/websocketProgramUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/accounts/websocketProgramUserAccountSubscriber.js +54 -0
- package/lib/node/addresses/marketAddresses.d.ts +3 -0
- package/lib/node/addresses/marketAddresses.d.ts.map +1 -0
- package/lib/node/addresses/marketAddresses.js +15 -0
- package/lib/node/addresses/pda.d.ts +48 -0
- package/lib/node/addresses/pda.d.ts.map +1 -0
- package/lib/node/addresses/pda.js +263 -0
- package/lib/node/adminClient.d.ts +403 -0
- package/lib/node/adminClient.d.ts.map +1 -0
- package/lib/node/adminClient.js +2798 -0
- package/lib/node/assert/assert.d.ts +2 -0
- package/lib/node/assert/assert.d.ts.map +1 -0
- package/lib/node/assert/assert.js +9 -0
- package/lib/node/auctionSubscriber/auctionSubscriber.d.ts +15 -0
- package/lib/node/auctionSubscriber/auctionSubscriber.d.ts.map +1 -0
- package/lib/node/auctionSubscriber/auctionSubscriber.js +32 -0
- package/lib/node/auctionSubscriber/auctionSubscriberGrpc.d.ts +16 -0
- package/lib/node/auctionSubscriber/auctionSubscriberGrpc.d.ts.map +1 -0
- package/lib/node/auctionSubscriber/auctionSubscriberGrpc.js +32 -0
- package/lib/node/auctionSubscriber/index.d.ts +4 -0
- package/lib/node/auctionSubscriber/index.d.ts.map +1 -0
- package/lib/node/auctionSubscriber/index.js +19 -0
- package/lib/node/auctionSubscriber/types.d.ts +15 -0
- package/lib/node/auctionSubscriber/types.d.ts.map +1 -0
- package/lib/node/auctionSubscriber/types.js +2 -0
- package/lib/node/bankrun/bankrunConnection.d.ts +77 -0
- package/lib/node/bankrun/bankrunConnection.d.ts.map +1 -0
- package/lib/node/bankrun/bankrunConnection.js +348 -0
- package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts +28 -0
- package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts.map +1 -0
- package/lib/node/blockhashSubscriber/BlockhashSubscriber.js +89 -0
- package/lib/node/blockhashSubscriber/index.d.ts +2 -0
- package/lib/node/blockhashSubscriber/index.d.ts.map +1 -0
- package/lib/node/blockhashSubscriber/index.js +17 -0
- package/lib/node/blockhashSubscriber/types.d.ts +8 -0
- package/lib/node/blockhashSubscriber/types.d.ts.map +1 -0
- package/lib/node/blockhashSubscriber/types.js +2 -0
- package/lib/node/clock/clockSubscriber.d.ts +32 -0
- package/lib/node/clock/clockSubscriber.d.ts.map +1 -0
- package/lib/node/clock/clockSubscriber.js +80 -0
- package/lib/node/config.d.ts +76 -0
- package/lib/node/config.d.ts.map +1 -0
- package/lib/node/config.js +164 -0
- package/lib/node/constants/index.d.ts +11 -0
- package/lib/node/constants/index.d.ts.map +1 -0
- package/lib/node/constants/index.js +26 -0
- package/lib/node/constants/insuranceFund.d.ts +6 -0
- package/lib/node/constants/insuranceFund.d.ts.map +1 -0
- package/lib/node/constants/insuranceFund.js +9 -0
- package/lib/node/constants/numericConstants.d.ts +74 -0
- package/lib/node/constants/numericConstants.d.ts.map +1 -0
- package/lib/node/constants/numericConstants.js +79 -0
- package/lib/node/constants/perpMarkets.d.ts +22 -0
- package/lib/node/constants/perpMarkets.d.ts.map +1 -0
- package/lib/node/constants/perpMarkets.js +971 -0
- package/lib/node/constants/spotMarkets.d.ts +25 -0
- package/lib/node/constants/spotMarkets.d.ts.map +1 -0
- package/lib/node/constants/spotMarkets.js +797 -0
- package/lib/node/constants/txConstants.d.ts +2 -0
- package/lib/node/constants/txConstants.d.ts.map +1 -0
- package/lib/node/constants/txConstants.js +4 -0
- package/lib/node/constituentMap/constituentMap.d.ts +67 -0
- package/lib/node/constituentMap/constituentMap.d.ts.map +1 -0
- package/lib/node/constituentMap/constituentMap.js +177 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.d.ts +25 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.d.ts.map +1 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.js +60 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.d.ts +25 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.d.ts.map +1 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.js +58 -0
- package/lib/node/core/VelocityCore.d.ts +227 -0
- package/lib/node/core/VelocityCore.d.ts.map +1 -0
- package/lib/node/core/VelocityCore.js +138 -0
- package/lib/node/core/index.d.ts +13 -0
- package/lib/node/core/index.d.ts.map +1 -0
- package/lib/node/core/index.js +28 -0
- package/lib/node/core/instructions/deposit.d.ts +20 -0
- package/lib/node/core/instructions/deposit.d.ts.map +1 -0
- package/lib/node/core/instructions/deposit.js +19 -0
- package/lib/node/core/instructions/fill.d.ts +14 -0
- package/lib/node/core/instructions/fill.d.ts.map +1 -0
- package/lib/node/core/instructions/fill.js +17 -0
- package/lib/node/core/instructions/funding.d.ts +10 -0
- package/lib/node/core/instructions/funding.d.ts.map +1 -0
- package/lib/node/core/instructions/funding.js +13 -0
- package/lib/node/core/instructions/liquidation.d.ts +16 -0
- package/lib/node/core/instructions/liquidation.d.ts.map +1 -0
- package/lib/node/core/instructions/liquidation.js +17 -0
- package/lib/node/core/instructions/orders.d.ts +23 -0
- package/lib/node/core/instructions/orders.d.ts.map +1 -0
- package/lib/node/core/instructions/orders.js +27 -0
- package/lib/node/core/instructions/perpOrders.d.ts +79 -0
- package/lib/node/core/instructions/perpOrders.d.ts.map +1 -0
- package/lib/node/core/instructions/perpOrders.js +99 -0
- package/lib/node/core/instructions/settlement.d.ts +12 -0
- package/lib/node/core/instructions/settlement.d.ts.map +1 -0
- package/lib/node/core/instructions/settlement.js +15 -0
- package/lib/node/core/instructions/trigger.d.ts +12 -0
- package/lib/node/core/instructions/trigger.d.ts.map +1 -0
- package/lib/node/core/instructions/trigger.js +15 -0
- package/lib/node/core/instructions/withdraw.d.ts +21 -0
- package/lib/node/core/instructions/withdraw.d.ts.map +1 -0
- package/lib/node/core/instructions/withdraw.js +20 -0
- package/lib/node/core/remainingAccounts.d.ts +28 -0
- package/lib/node/core/remainingAccounts.d.ts.map +1 -0
- package/lib/node/core/remainingAccounts.js +122 -0
- package/lib/node/core/signedMsg.d.ts +18 -0
- package/lib/node/core/signedMsg.d.ts.map +1 -0
- package/lib/node/core/signedMsg.js +39 -0
- package/lib/node/decode/customCoder.d.ts +45 -0
- package/lib/node/decode/customCoder.d.ts.map +1 -0
- package/lib/node/decode/customCoder.js +64 -0
- package/lib/node/decode/user.d.ts +5 -0
- package/lib/node/decode/user.d.ts.map +1 -0
- package/lib/node/decode/user.js +337 -0
- package/lib/node/dlob/DLOB.d.ts +254 -0
- package/lib/node/dlob/DLOB.d.ts.map +1 -0
- package/lib/node/dlob/DLOB.js +1137 -0
- package/lib/node/dlob/DLOBNode.d.ts +71 -0
- package/lib/node/dlob/DLOBNode.d.ts.map +1 -0
- package/lib/node/dlob/DLOBNode.js +103 -0
- package/lib/node/dlob/DLOBSubscriber.d.ts +58 -0
- package/lib/node/dlob/DLOBSubscriber.d.ts.map +1 -0
- package/lib/node/dlob/DLOBSubscriber.js +143 -0
- package/lib/node/dlob/NodeList.d.ts +28 -0
- package/lib/node/dlob/NodeList.d.ts.map +1 -0
- package/lib/node/dlob/NodeList.js +126 -0
- package/lib/node/dlob/orderBookLevels.d.ts +78 -0
- package/lib/node/dlob/orderBookLevels.d.ts.map +1 -0
- package/lib/node/dlob/orderBookLevels.js +404 -0
- package/lib/node/dlob/types.d.ts +19 -0
- package/lib/node/dlob/types.d.ts.map +1 -0
- package/lib/node/dlob/types.js +2 -0
- package/lib/node/events/eventList.d.ts +23 -0
- package/lib/node/events/eventList.d.ts.map +1 -0
- package/lib/node/events/eventList.js +80 -0
- package/lib/node/events/eventSubscriber.d.ts +56 -0
- package/lib/node/events/eventSubscriber.d.ts.map +1 -0
- package/lib/node/events/eventSubscriber.js +229 -0
- package/lib/node/events/eventsServerLogProvider.d.ts +22 -0
- package/lib/node/events/eventsServerLogProvider.d.ts.map +1 -0
- package/lib/node/events/eventsServerLogProvider.js +121 -0
- package/lib/node/events/fetchLogs.d.ts +26 -0
- package/lib/node/events/fetchLogs.d.ts.map +1 -0
- package/lib/node/events/fetchLogs.js +99 -0
- package/lib/node/events/parse.d.ts +9 -0
- package/lib/node/events/parse.d.ts.map +1 -0
- package/lib/node/events/parse.js +199 -0
- package/lib/node/events/pollingLogProvider.d.ts +18 -0
- package/lib/node/events/pollingLogProvider.d.ts.map +1 -0
- package/lib/node/events/pollingLogProvider.js +58 -0
- package/lib/node/events/sort.d.ts +3 -0
- package/lib/node/events/sort.d.ts.map +1 -0
- package/lib/node/events/sort.js +24 -0
- package/lib/node/events/txEventCache.d.ts +25 -0
- package/lib/node/events/txEventCache.d.ts.map +1 -0
- package/lib/node/events/txEventCache.js +71 -0
- package/lib/node/events/types.d.ts +105 -0
- package/lib/node/events/types.d.ts.map +1 -0
- package/lib/node/events/types.js +36 -0
- package/lib/node/events/webSocketLogProvider.d.ts +25 -0
- package/lib/node/events/webSocketLogProvider.d.ts.map +1 -0
- package/lib/node/events/webSocketLogProvider.js +96 -0
- package/lib/node/factory/bigNum.d.ts +123 -0
- package/lib/node/factory/bigNum.d.ts.map +1 -0
- package/lib/node/factory/bigNum.js +500 -0
- package/lib/node/factory/oracleClient.d.ts +6 -0
- package/lib/node/factory/oracleClient.d.ts.map +1 -0
- package/lib/node/factory/oracleClient.js +53 -0
- package/lib/node/idl/drift.d.ts +23895 -0
- package/lib/node/idl/drift.d.ts.map +1 -0
- package/lib/node/idl/drift.js +2 -0
- package/lib/node/idl/drift.json +18698 -0
- package/lib/node/idl/pyth.d.ts +98 -0
- package/lib/node/idl/pyth.d.ts.map +1 -0
- package/lib/node/idl/pyth.js +2 -0
- package/lib/node/idl/token_faucet.d.ts +198 -0
- package/lib/node/idl/token_faucet.d.ts.map +1 -0
- package/lib/node/idl/token_faucet.js +2 -0
- package/lib/node/idl/token_faucet.json +229 -0
- package/lib/node/index.d.ts +145 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +175 -0
- package/lib/node/indicative-quotes/indicativeQuotesSender.d.ts +36 -0
- package/lib/node/indicative-quotes/indicativeQuotesSender.d.ts.map +1 -0
- package/lib/node/indicative-quotes/indicativeQuotesSender.js +192 -0
- package/lib/node/isomorphic/anchor.browser.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor.d.ts +2 -0
- package/lib/node/isomorphic/anchor.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor.js +17 -0
- package/lib/node/isomorphic/anchor.node.d.ts +2 -0
- package/lib/node/isomorphic/anchor.node.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor.node.js +17 -0
- package/lib/node/isomorphic/anchor29.browser.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor29.d.ts +2 -0
- package/lib/node/isomorphic/anchor29.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor29.js +17 -0
- package/lib/node/isomorphic/anchor29.node.d.ts +2 -0
- package/lib/node/isomorphic/anchor29.node.d.ts.map +1 -0
- package/lib/node/isomorphic/anchor29.node.js +17 -0
- package/lib/node/isomorphic/grpc.browser.d.ts.map +1 -0
- package/lib/node/isomorphic/grpc.d.ts +18 -0
- package/lib/node/isomorphic/grpc.d.ts.map +1 -0
- package/lib/node/isomorphic/grpc.js +109 -0
- package/lib/node/isomorphic/grpc.node.d.ts +18 -0
- package/lib/node/isomorphic/grpc.node.d.ts.map +1 -0
- package/lib/node/isomorphic/grpc.node.js +109 -0
- package/lib/node/jupiter/jupiterClient.d.ts +292 -0
- package/lib/node/jupiter/jupiterClient.d.ts.map +1 -0
- package/lib/node/jupiter/jupiterClient.js +164 -0
- package/lib/node/keypair.d.ts +3 -0
- package/lib/node/keypair.d.ts.map +1 -0
- package/lib/node/keypair.js +28 -0
- package/lib/node/marginCalculation.d.ts +68 -0
- package/lib/node/marginCalculation.d.ts.map +1 -0
- package/lib/node/marginCalculation.js +176 -0
- package/lib/node/marinade/index.d.ts +13 -0
- package/lib/node/marinade/index.d.ts.map +1 -0
- package/lib/node/marinade/index.js +36 -0
- package/lib/node/marinade/types.d.ts +1964 -0
- package/lib/node/marinade/types.d.ts.map +1 -0
- package/lib/node/marinade/types.js +1965 -0
- package/lib/node/math/amm.d.ts +99 -0
- package/lib/node/math/amm.d.ts.map +1 -0
- package/lib/node/math/amm.js +671 -0
- package/lib/node/math/auction.d.ts +66 -0
- package/lib/node/math/auction.d.ts.map +1 -0
- package/lib/node/math/auction.js +261 -0
- package/lib/node/math/bankruptcy.d.ts +3 -0
- package/lib/node/math/bankruptcy.d.ts.map +1 -0
- package/lib/node/math/bankruptcy.js +32 -0
- package/lib/node/math/builder.d.ts +6 -0
- package/lib/node/math/builder.d.ts.map +1 -0
- package/lib/node/math/builder.js +22 -0
- package/lib/node/math/conversion.d.ts +5 -0
- package/lib/node/math/conversion.d.ts.map +1 -0
- package/lib/node/math/conversion.js +21 -0
- package/lib/node/math/exchangeStatus.d.ts +9 -0
- package/lib/node/math/exchangeStatus.d.ts.map +1 -0
- package/lib/node/math/exchangeStatus.js +85 -0
- package/lib/node/math/funding.d.ts +45 -0
- package/lib/node/math/funding.d.ts.map +1 -0
- package/lib/node/math/funding.js +260 -0
- package/lib/node/math/insurance.d.ts +9 -0
- package/lib/node/math/insurance.d.ts.map +1 -0
- package/lib/node/math/insurance.js +74 -0
- package/lib/node/math/liquidation.d.ts +8 -0
- package/lib/node/math/liquidation.d.ts.map +1 -0
- package/lib/node/math/liquidation.js +134 -0
- package/lib/node/math/margin.d.ts +46 -0
- package/lib/node/math/margin.d.ts.map +1 -0
- package/lib/node/math/margin.js +205 -0
- package/lib/node/math/market.d.ts +51 -0
- package/lib/node/math/market.d.ts.map +1 -0
- package/lib/node/math/market.js +234 -0
- package/lib/node/math/oracles.d.ts +20 -0
- package/lib/node/math/oracles.d.ts.map +1 -0
- package/lib/node/math/oracles.js +215 -0
- package/lib/node/math/orders.d.ts +37 -0
- package/lib/node/math/orders.d.ts.map +1 -0
- package/lib/node/math/orders.js +294 -0
- package/lib/node/math/position.d.ts +72 -0
- package/lib/node/math/position.d.ts.map +1 -0
- package/lib/node/math/position.js +232 -0
- package/lib/node/math/repeg.d.ts +23 -0
- package/lib/node/math/repeg.d.ts.map +1 -0
- package/lib/node/math/repeg.js +164 -0
- package/lib/node/math/spotBalance.d.ts +86 -0
- package/lib/node/math/spotBalance.d.ts.map +1 -0
- package/lib/node/math/spotBalance.js +438 -0
- package/lib/node/math/spotMarket.d.ts +12 -0
- package/lib/node/math/spotMarket.d.ts.map +1 -0
- package/lib/node/math/spotMarket.js +49 -0
- package/lib/node/math/spotPosition.d.ts +20 -0
- package/lib/node/math/spotPosition.d.ts.map +1 -0
- package/lib/node/math/spotPosition.js +79 -0
- package/lib/node/math/state.d.ts +9 -0
- package/lib/node/math/state.d.ts.map +1 -0
- package/lib/node/math/state.js +44 -0
- package/lib/node/math/superStake.d.ts +169 -0
- package/lib/node/math/superStake.d.ts.map +1 -0
- package/lib/node/math/superStake.js +308 -0
- package/lib/node/math/tiers.d.ts +5 -0
- package/lib/node/math/tiers.d.ts.map +1 -0
- package/lib/node/math/tiers.js +52 -0
- package/lib/node/math/trade.d.ts +94 -0
- package/lib/node/math/trade.d.ts.map +1 -0
- package/lib/node/math/trade.js +503 -0
- package/lib/node/math/utils.d.ts +24 -0
- package/lib/node/math/utils.d.ts.map +1 -0
- package/lib/node/math/utils.js +113 -0
- package/lib/node/memcmp.d.ts +19 -0
- package/lib/node/memcmp.d.ts.map +1 -0
- package/lib/node/memcmp.js +162 -0
- package/lib/node/oracles/oracleClientCache.d.ts +10 -0
- package/lib/node/oracles/oracleClientCache.d.ts.map +1 -0
- package/lib/node/oracles/oracleClientCache.js +19 -0
- package/lib/node/oracles/oracleId.d.ts +10 -0
- package/lib/node/oracles/oracleId.d.ts.map +1 -0
- package/lib/node/oracles/oracleId.js +89 -0
- package/lib/node/oracles/prelaunchOracleClient.d.ts +13 -0
- package/lib/node/oracles/prelaunchOracleClient.d.ts.map +1 -0
- package/lib/node/oracles/prelaunchOracleClient.js +24 -0
- package/lib/node/oracles/pythClient.d.ts +15 -0
- package/lib/node/oracles/pythClient.d.ts.map +1 -0
- package/lib/node/oracles/pythClient.js +51 -0
- package/lib/node/oracles/pythLazerClient.d.ts +17 -0
- package/lib/node/oracles/pythLazerClient.d.ts.map +1 -0
- package/lib/node/oracles/pythLazerClient.js +61 -0
- package/lib/node/oracles/quoteAssetOracleClient.d.ts +11 -0
- package/lib/node/oracles/quoteAssetOracleClient.d.ts.map +1 -0
- package/lib/node/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/node/oracles/strictOraclePrice.d.ts +10 -0
- package/lib/node/oracles/strictOraclePrice.d.ts.map +1 -0
- package/lib/node/oracles/strictOraclePrice.js +17 -0
- package/lib/node/oracles/types.d.ts +34 -0
- package/lib/node/oracles/types.d.ts.map +1 -0
- package/lib/node/oracles/types.js +2 -0
- package/lib/node/oracles/utils.d.ts +5 -0
- package/lib/node/oracles/utils.d.ts.map +1 -0
- package/lib/node/oracles/utils.js +8 -0
- package/lib/node/orderParams.d.ts +30 -0
- package/lib/node/orderParams.d.ts.map +1 -0
- package/lib/node/orderParams.js +44 -0
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts +46 -0
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -0
- package/lib/node/orderSubscriber/OrderSubscriber.js +193 -0
- package/lib/node/orderSubscriber/PollingSubscription.d.ts +13 -0
- package/lib/node/orderSubscriber/PollingSubscription.d.ts.map +1 -0
- package/lib/node/orderSubscriber/PollingSubscription.js +23 -0
- package/lib/node/orderSubscriber/WebsocketSubscription.d.ts +24 -0
- package/lib/node/orderSubscriber/WebsocketSubscription.d.ts.map +1 -0
- package/lib/node/orderSubscriber/WebsocketSubscription.js +67 -0
- package/lib/node/orderSubscriber/grpcSubscription.d.ts +23 -0
- package/lib/node/orderSubscriber/grpcSubscription.d.ts.map +1 -0
- package/lib/node/orderSubscriber/grpcSubscription.js +75 -0
- package/lib/node/orderSubscriber/index.d.ts +8 -0
- package/lib/node/orderSubscriber/index.d.ts.map +1 -0
- package/lib/node/orderSubscriber/index.js +23 -0
- package/lib/node/orderSubscriber/types.d.ts +36 -0
- package/lib/node/orderSubscriber/types.d.ts.map +1 -0
- package/lib/node/orderSubscriber/types.js +2 -0
- package/lib/node/priorityFee/averageOverSlotsStrategy.d.ts +6 -0
- package/lib/node/priorityFee/averageOverSlotsStrategy.d.ts.map +1 -0
- package/lib/node/priorityFee/averageOverSlotsStrategy.js +16 -0
- package/lib/node/priorityFee/averageStrategy.d.ts +6 -0
- package/lib/node/priorityFee/averageStrategy.d.ts.map +1 -0
- package/lib/node/priorityFee/averageStrategy.js +11 -0
- package/lib/node/priorityFee/ewmaStrategy.d.ts +12 -0
- package/lib/node/priorityFee/ewmaStrategy.d.ts.map +1 -0
- package/lib/node/priorityFee/ewmaStrategy.js +33 -0
- package/lib/node/priorityFee/heliusPriorityFeeMethod.d.ts +21 -0
- package/lib/node/priorityFee/heliusPriorityFeeMethod.d.ts.map +1 -0
- package/lib/node/priorityFee/heliusPriorityFeeMethod.js +46 -0
- package/lib/node/priorityFee/index.d.ts +17 -0
- package/lib/node/priorityFee/index.d.ts.map +1 -0
- package/lib/node/priorityFee/index.js +32 -0
- package/lib/node/priorityFee/maxOverSlotsStrategy.d.ts +6 -0
- package/lib/node/priorityFee/maxOverSlotsStrategy.d.ts.map +1 -0
- package/lib/node/priorityFee/maxOverSlotsStrategy.js +17 -0
- package/lib/node/priorityFee/maxStrategy.d.ts +8 -0
- package/lib/node/priorityFee/maxStrategy.d.ts.map +1 -0
- package/lib/node/priorityFee/maxStrategy.js +9 -0
- package/lib/node/priorityFee/priorityFeeSubscriber.d.ts +49 -0
- package/lib/node/priorityFee/priorityFeeSubscriber.d.ts.map +1 -0
- package/lib/node/priorityFee/priorityFeeSubscriber.js +193 -0
- package/lib/node/priorityFee/priorityFeeSubscriberMap.d.ts +51 -0
- package/lib/node/priorityFee/priorityFeeSubscriberMap.d.ts.map +1 -0
- package/lib/node/priorityFee/priorityFeeSubscriberMap.js +96 -0
- package/lib/node/priorityFee/solanaPriorityFeeMethod.d.ts +7 -0
- package/lib/node/priorityFee/solanaPriorityFeeMethod.d.ts.map +1 -0
- package/lib/node/priorityFee/solanaPriorityFeeMethod.js +21 -0
- package/lib/node/priorityFee/types.d.ts +36 -0
- package/lib/node/priorityFee/types.d.ts.map +1 -0
- package/lib/node/priorityFee/types.js +10 -0
- package/lib/node/priorityFee/velocityPriorityFeeMethod.d.ts +22 -0
- package/lib/node/priorityFee/velocityPriorityFeeMethod.d.ts.map +1 -0
- package/lib/node/priorityFee/velocityPriorityFeeMethod.js +28 -0
- package/lib/node/pyth/constants.d.ts +4 -0
- package/lib/node/pyth/constants.d.ts.map +1 -0
- package/lib/node/pyth/constants.js +6 -0
- package/lib/node/pyth/index.d.ts +5 -0
- package/lib/node/pyth/index.d.ts.map +1 -0
- package/lib/node/pyth/index.js +12 -0
- package/lib/node/pyth/pythLazerSubscriber.d.ts +92 -0
- package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -0
- package/lib/node/pyth/pythLazerSubscriber.js +276 -0
- package/lib/node/pyth/types.d.ts +2227 -0
- package/lib/node/pyth/types.d.ts.map +1 -0
- package/lib/node/pyth/types.js +2224 -0
- package/lib/node/pyth/utils.d.ts +3 -0
- package/lib/node/pyth/utils.d.ts.map +1 -0
- package/lib/node/pyth/utils.js +10 -0
- package/lib/node/slot/SlotSubscriber.d.ts +28 -0
- package/lib/node/slot/SlotSubscriber.d.ts.map +1 -0
- package/lib/node/slot/SlotSubscriber.js +76 -0
- package/lib/node/slot/SlothashSubscriber.d.ts +26 -0
- package/lib/node/slot/SlothashSubscriber.d.ts.map +1 -0
- package/lib/node/slot/SlothashSubscriber.js +88 -0
- package/lib/node/swap/UnifiedSwapClient.d.ts +121 -0
- package/lib/node/swap/UnifiedSwapClient.d.ts.map +1 -0
- package/lib/node/swap/UnifiedSwapClient.js +179 -0
- package/lib/node/swift/grpcSignedMsgUserAccountSubscriber.d.ts +23 -0
- package/lib/node/swift/grpcSignedMsgUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/swift/grpcSignedMsgUserAccountSubscriber.js +57 -0
- package/lib/node/swift/index.d.ts +11 -0
- package/lib/node/swift/index.d.ts.map +1 -0
- package/lib/node/swift/index.js +26 -0
- package/lib/node/swift/signedMsgUserAccountSubscriber.d.ts +43 -0
- package/lib/node/swift/signedMsgUserAccountSubscriber.d.ts.map +1 -0
- package/lib/node/swift/signedMsgUserAccountSubscriber.js +118 -0
- package/lib/node/swift/swiftOrderSubscriber.d.ts +64 -0
- package/lib/node/swift/swiftOrderSubscriber.d.ts.map +1 -0
- package/lib/node/swift/swiftOrderSubscriber.js +187 -0
- package/lib/node/testClient.d.ts +9 -0
- package/lib/node/testClient.d.ts.map +1 -0
- package/lib/node/testClient.js +24 -0
- package/lib/node/titan/titanClient.d.ts +91 -0
- package/lib/node/titan/titanClient.d.ts.map +1 -0
- package/lib/node/titan/titanClient.js +227 -0
- package/lib/node/token/index.d.ts +6 -0
- package/lib/node/token/index.d.ts.map +1 -0
- package/lib/node/token/index.js +15 -0
- package/lib/node/tokenFaucet.d.ts +42 -0
- package/lib/node/tokenFaucet.d.ts.map +1 -0
- package/lib/node/tokenFaucet.js +188 -0
- package/lib/node/tx/baseTxSender.d.ts +60 -0
- package/lib/node/tx/baseTxSender.d.ts.map +1 -0
- package/lib/node/tx/baseTxSender.js +292 -0
- package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.d.ts +9 -0
- package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.d.ts.map +1 -0
- package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.js +13 -0
- package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts +29 -0
- package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts.map +1 -0
- package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.js +73 -0
- package/lib/node/tx/blockhashFetcher/types.d.ts +5 -0
- package/lib/node/tx/blockhashFetcher/types.d.ts.map +1 -0
- package/lib/node/tx/blockhashFetcher/types.js +2 -0
- package/lib/node/tx/fastSingleTxSender.d.ts +42 -0
- package/lib/node/tx/fastSingleTxSender.d.ts.map +1 -0
- package/lib/node/tx/fastSingleTxSender.js +86 -0
- package/lib/node/tx/forwardOnlyTxSender.d.ts +38 -0
- package/lib/node/tx/forwardOnlyTxSender.d.ts.map +1 -0
- package/lib/node/tx/forwardOnlyTxSender.js +92 -0
- package/lib/node/tx/priorityFeeCalculator.d.ts +45 -0
- package/lib/node/tx/priorityFeeCalculator.d.ts.map +1 -0
- package/lib/node/tx/priorityFeeCalculator.js +85 -0
- package/lib/node/tx/reportTransactionError.d.ts +21 -0
- package/lib/node/tx/reportTransactionError.d.ts.map +1 -0
- package/lib/node/tx/reportTransactionError.js +103 -0
- package/lib/node/tx/retryTxSender.d.ts +38 -0
- package/lib/node/tx/retryTxSender.d.ts.map +1 -0
- package/lib/node/tx/retryTxSender.js +86 -0
- package/lib/node/tx/txHandler.d.ts +174 -0
- package/lib/node/tx/txHandler.d.ts.map +1 -0
- package/lib/node/tx/txHandler.js +522 -0
- package/lib/node/tx/txParamProcessor.d.ts +27 -0
- package/lib/node/tx/txParamProcessor.d.ts.map +1 -0
- package/lib/node/tx/txParamProcessor.js +92 -0
- package/lib/node/tx/types.d.ts +30 -0
- package/lib/node/tx/types.d.ts.map +1 -0
- package/lib/node/tx/types.js +20 -0
- package/lib/node/tx/utils.d.ts +7 -0
- package/lib/node/tx/utils.d.ts.map +1 -0
- package/lib/node/tx/utils.js +78 -0
- package/lib/node/tx/whileValidTxSender.d.ts +46 -0
- package/lib/node/tx/whileValidTxSender.d.ts.map +1 -0
- package/lib/node/tx/whileValidTxSender.js +168 -0
- package/lib/node/types.d.ts +1748 -0
- package/lib/node/types.d.ts.map +1 -0
- package/lib/node/types.js +427 -0
- package/lib/node/user.d.ts +447 -0
- package/lib/node/user.d.ts.map +1 -0
- package/lib/node/user.js +2372 -0
- package/lib/node/userConfig.d.ts +32 -0
- package/lib/node/userConfig.d.ts.map +1 -0
- package/lib/node/userConfig.js +2 -0
- package/lib/node/userMap/PollingSubscription.d.ts +16 -0
- package/lib/node/userMap/PollingSubscription.d.ts.map +1 -0
- package/lib/node/userMap/PollingSubscription.js +30 -0
- package/lib/node/userMap/WebsocketSubscription.d.ts +28 -0
- package/lib/node/userMap/WebsocketSubscription.d.ts.map +1 -0
- package/lib/node/userMap/WebsocketSubscription.js +45 -0
- package/lib/node/userMap/grpcSubscription.d.ts +28 -0
- package/lib/node/userMap/grpcSubscription.d.ts.map +1 -0
- package/lib/node/userMap/grpcSubscription.js +44 -0
- package/lib/node/userMap/referrerMap.d.ts +46 -0
- package/lib/node/userMap/referrerMap.d.ts.map +1 -0
- package/lib/node/userMap/referrerMap.js +184 -0
- package/lib/node/userMap/revenueShareEscrowMap.d.ts +67 -0
- package/lib/node/userMap/revenueShareEscrowMap.d.ts.map +1 -0
- package/lib/node/userMap/revenueShareEscrowMap.js +210 -0
- package/lib/node/userMap/userMap.d.ts +115 -0
- package/lib/node/userMap/userMap.d.ts.map +1 -0
- package/lib/node/userMap/userMap.js +486 -0
- package/lib/node/userMap/userMapConfig.d.ts +41 -0
- package/lib/node/userMap/userMapConfig.d.ts.map +1 -0
- package/lib/node/userMap/userMapConfig.js +2 -0
- package/lib/node/userMap/userStatsMap.d.ts +67 -0
- package/lib/node/userMap/userStatsMap.d.ts.map +1 -0
- package/lib/node/userMap/userStatsMap.js +266 -0
- package/lib/node/userName.d.ts +6 -0
- package/lib/node/userName.d.ts.map +1 -0
- package/lib/node/userName.js +21 -0
- package/lib/node/userStats.d.ts +25 -0
- package/lib/node/userStats.d.ts.map +1 -0
- package/lib/node/userStats.js +70 -0
- package/lib/node/userStatsConfig.d.ts +27 -0
- package/lib/node/userStatsConfig.d.ts.map +1 -0
- package/lib/node/userStatsConfig.js +2 -0
- package/lib/node/util/TransactionConfirmationManager.d.ts +17 -0
- package/lib/node/util/TransactionConfirmationManager.d.ts.map +1 -0
- package/lib/node/util/TransactionConfirmationManager.js +174 -0
- package/lib/node/util/chainClock.d.ts +18 -0
- package/lib/node/util/chainClock.d.ts.map +1 -0
- package/lib/node/util/chainClock.js +29 -0
- package/lib/node/util/computeUnits.d.ts +9 -0
- package/lib/node/util/computeUnits.d.ts.map +1 -0
- package/lib/node/util/computeUnits.js +48 -0
- package/lib/node/util/digest.d.ts +6 -0
- package/lib/node/util/digest.d.ts.map +1 -0
- package/lib/node/util/digest.js +19 -0
- package/lib/node/util/ed25519Utils.d.ts +11 -0
- package/lib/node/util/ed25519Utils.d.ts.map +1 -0
- package/lib/node/util/ed25519Utils.js +80 -0
- package/lib/node/util/promiseTimeout.d.ts +2 -0
- package/lib/node/util/promiseTimeout.d.ts.map +1 -0
- package/lib/node/util/promiseTimeout.js +14 -0
- package/lib/node/util/tps.d.ts +3 -0
- package/lib/node/util/tps.d.ts.map +1 -0
- package/lib/node/util/tps.js +16 -0
- package/lib/node/velocityClient.d.ts +1231 -0
- package/lib/node/velocityClient.d.ts.map +1 -0
- package/lib/node/velocityClient.js +5778 -0
- package/lib/node/velocityClientConfig.d.ts +85 -0
- package/lib/node/velocityClientConfig.d.ts.map +1 -0
- package/lib/node/velocityClientConfig.js +2 -0
- package/lib/node/wallet.d.ts +17 -0
- package/lib/node/wallet.d.ts.map +1 -0
- package/lib/node/wallet.js +46 -0
- package/package.json +157 -0
- package/scripts/deposit-isolated-positions.ts +110 -0
- package/scripts/find-flagged-users.ts +213 -0
- package/scripts/grpc-client-test-comparison.ts +372 -0
- package/scripts/grpc-multiuser-client-test-comparison.ts +158 -0
- package/scripts/postbuild.js +95 -0
- package/scripts/single-grpc-client-test.ts +284 -0
- package/scripts/updateVersion.js +28 -0
- package/scripts/withdraw-isolated-positions.ts +174 -0
- package/src/accounts/README_WebSocketAccountSubscriberV2.md +95 -0
- package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +135 -0
- package/src/accounts/basicUserAccountSubscriber.ts +59 -0
- package/src/accounts/basicUserStatsAccountSubscriber.ts +65 -0
- package/src/accounts/bulkAccountLoader.ts +293 -0
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +33 -0
- package/src/accounts/customizedCadenceBulkAccountLoader.ts +213 -0
- package/src/accounts/fetch.ts +143 -0
- package/src/accounts/grpcAccountSubscriber.ts +187 -0
- package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +57 -0
- package/src/accounts/grpcMultiAccountSubscriber.ts +476 -0
- package/src/accounts/grpcMultiUserAccountSubscriber.ts +281 -0
- package/src/accounts/grpcProgramAccountSubscriber.ts +223 -0
- package/src/accounts/grpcUserAccountSubscriber.ts +48 -0
- package/src/accounts/grpcUserStatsAccountSubscriber.ts +50 -0
- package/src/accounts/grpcVelocityClientAccountSubscriber.ts +213 -0
- package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +762 -0
- package/src/accounts/laserProgramAccountSubscriber.ts +229 -0
- package/src/accounts/oneShotUserAccountSubscriber.ts +67 -0
- package/src/accounts/oneShotUserStatsAccountSubscriber.ts +70 -0
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +186 -0
- package/src/accounts/pollingOracleAccountSubscriber.ts +125 -0
- package/src/accounts/pollingTokenAccountSubscriber.ts +118 -0
- package/src/accounts/pollingUserAccountSubscriber.ts +160 -0
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +156 -0
- package/src/accounts/pollingVelocityClientAccountSubscriber.ts +652 -0
- package/src/accounts/testBulkAccountLoader.ts +51 -0
- package/src/accounts/types.ts +284 -0
- package/src/accounts/utils.ts +62 -0
- package/src/accounts/webSocketAccountSubscriber.ts +250 -0
- package/src/accounts/webSocketAccountSubscriberV2.ts +517 -0
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +129 -0
- package/src/accounts/webSocketProgramAccountSubscriber.ts +183 -0
- package/src/accounts/webSocketProgramAccountSubscriberV2.ts +996 -0
- package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +996 -0
- package/src/accounts/webSocketUserAccountSubscriber.ts +104 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +98 -0
- package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +719 -0
- package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +755 -0
- package/src/accounts/websocketProgramUserAccountSubscriber.ts +94 -0
- package/src/addresses/marketAddresses.ts +17 -0
- package/src/addresses/pda.ts +439 -0
- package/src/adminClient.ts +5936 -0
- package/src/assert/assert.ts +5 -0
- package/src/auctionSubscriber/auctionSubscriber.ts +68 -0
- package/src/auctionSubscriber/auctionSubscriberGrpc.ts +72 -0
- package/src/auctionSubscriber/index.ts +3 -0
- package/src/auctionSubscriber/types.ts +20 -0
- package/src/bankrun/bankrunConnection.ts +560 -0
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +126 -0
- package/src/blockhashSubscriber/index.ts +1 -0
- package/src/blockhashSubscriber/types.ts +12 -0
- package/src/clock/clockSubscriber.ts +121 -0
- package/src/config.ts +268 -0
- package/src/constants/index.ts +10 -0
- package/src/constants/insuranceFund.ts +8 -0
- package/src/constants/numericConstants.ts +119 -0
- package/src/constants/perpMarkets.ts +1042 -0
- package/src/constants/spotMarkets.ts +874 -0
- package/src/constants/txConstants.ts +1 -0
- package/src/constituentMap/constituentMap.ts +294 -0
- package/src/constituentMap/pollingConstituentAccountSubscriber.ts +97 -0
- package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +112 -0
- package/src/core/VelocityCore.ts +331 -0
- package/src/core/index.ts +12 -0
- package/src/core/instructions/deposit.ts +42 -0
- package/src/core/instructions/fill.ts +34 -0
- package/src/core/instructions/funding.ts +21 -0
- package/src/core/instructions/liquidation.ts +37 -0
- package/src/core/instructions/orders.ts +56 -0
- package/src/core/instructions/perpOrders.ts +192 -0
- package/src/core/instructions/settlement.ts +26 -0
- package/src/core/instructions/trigger.ts +26 -0
- package/src/core/instructions/withdraw.ts +44 -0
- package/src/core/remainingAccounts.ts +276 -0
- package/src/core/signedMsg.ts +71 -0
- package/src/decode/customCoder.ts +105 -0
- package/src/decode/user.ts +372 -0
- package/src/dlob/DLOB.ts +2098 -0
- package/src/dlob/DLOBNode.ts +193 -0
- package/src/dlob/DLOBSubscriber.ts +211 -0
- package/src/dlob/NodeList.ts +174 -0
- package/src/dlob/orderBookLevels.ts +575 -0
- package/src/dlob/types.ts +22 -0
- package/src/events/eventList.ts +97 -0
- package/src/events/eventSubscriber.ts +382 -0
- package/src/events/eventsServerLogProvider.ts +152 -0
- package/src/events/fetchLogs.ts +169 -0
- package/src/events/parse.ts +248 -0
- package/src/events/pollingLogProvider.ts +89 -0
- package/src/events/sort.ts +39 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.ts +228 -0
- package/src/events/webSocketLogProvider.ts +121 -0
- package/src/factory/bigNum.ts +709 -0
- package/src/factory/oracleClient.ts +73 -0
- package/src/idl/drift.json +18698 -0
- package/src/idl/drift.ts +23894 -0
- package/src/idl/pyth.json +142 -0
- package/src/idl/pyth.ts +97 -0
- package/src/idl/pyth_solana_receiver.json +628 -0
- package/src/idl/token_faucet.json +229 -0
- package/src/idl/token_faucet.ts +197 -0
- package/src/index.ts +150 -0
- package/src/indicative-quotes/indicativeQuotesSender.ts +233 -0
- package/src/isomorphic/README.md +19 -0
- package/src/isomorphic/anchor.browser.ts +44 -0
- package/src/isomorphic/anchor.node.ts +1 -0
- package/src/isomorphic/anchor.ts +1 -0
- package/src/isomorphic/anchor29.browser.ts +24 -0
- package/src/isomorphic/anchor29.node.ts +1 -0
- package/src/isomorphic/anchor29.ts +1 -0
- package/src/isomorphic/grpc.browser.ts +4 -0
- package/src/isomorphic/grpc.node.ts +130 -0
- package/src/isomorphic/grpc.ts +1 -0
- package/src/jupiter/jupiterClient.ts +482 -0
- package/src/keypair.ts +24 -0
- package/src/margin/README.md +138 -0
- package/src/marginCalculation.ts +255 -0
- package/src/marinade/idl/idl.json +1962 -0
- package/src/marinade/index.ts +64 -0
- package/src/marinade/types.ts +3925 -0
- package/src/math/amm.ts +1246 -0
- package/src/math/auction.ts +374 -0
- package/src/math/bankruptcy.ts +35 -0
- package/src/math/builder.ts +20 -0
- package/src/math/conversion.ts +24 -0
- package/src/math/exchangeStatus.ts +136 -0
- package/src/math/funding.ts +436 -0
- package/src/math/insurance.ts +111 -0
- package/src/math/liquidation.ts +209 -0
- package/src/math/margin.ts +368 -0
- package/src/math/market.ts +438 -0
- package/src/math/oracles.ts +367 -0
- package/src/math/orders.ts +473 -0
- package/src/math/position.ts +340 -0
- package/src/math/repeg.ts +214 -0
- package/src/math/spotBalance.ts +752 -0
- package/src/math/spotMarket.ts +82 -0
- package/src/math/spotPosition.ts +191 -0
- package/src/math/state.ts +48 -0
- package/src/math/superStake.ts +528 -0
- package/src/math/tiers.ts +44 -0
- package/src/math/trade.ts +805 -0
- package/src/math/utils.ts +121 -0
- package/src/memcmp.ts +164 -0
- package/src/oracles/oracleClientCache.ts +25 -0
- package/src/oracles/oracleId.ts +66 -0
- package/src/oracles/prelaunchOracleClient.ts +38 -0
- package/src/oracles/pythClient.ts +85 -0
- package/src/oracles/pythLazerClient.ts +102 -0
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/strictOraclePrice.ts +19 -0
- package/src/oracles/types.ts +37 -0
- package/src/oracles/utils.ts +10 -0
- package/src/orderParams.ts +79 -0
- package/src/orderSubscriber/OrderSubscriber.ts +296 -0
- package/src/orderSubscriber/PollingSubscription.ts +39 -0
- package/src/orderSubscriber/WebsocketSubscription.ts +119 -0
- package/src/orderSubscriber/grpcSubscription.ts +139 -0
- package/src/orderSubscriber/index.ts +7 -0
- package/src/orderSubscriber/types.ts +55 -0
- package/src/priorityFee/averageOverSlotsStrategy.ts +16 -0
- package/src/priorityFee/averageStrategy.ts +12 -0
- package/src/priorityFee/ewmaStrategy.ts +41 -0
- package/src/priorityFee/heliusPriorityFeeMethod.ts +57 -0
- package/src/priorityFee/index.ts +16 -0
- package/src/priorityFee/maxOverSlotsStrategy.ts +17 -0
- package/src/priorityFee/maxStrategy.ts +7 -0
- package/src/priorityFee/priorityFeeSubscriber.ts +256 -0
- package/src/priorityFee/priorityFeeSubscriberMap.ts +125 -0
- package/src/priorityFee/solanaPriorityFeeMethod.ts +34 -0
- package/src/priorityFee/types.ts +64 -0
- package/src/priorityFee/velocityPriorityFeeMethod.ts +54 -0
- package/src/pyth/constants.ts +9 -0
- package/src/pyth/index.ts +15 -0
- package/src/pyth/pythLazerSubscriber.ts +365 -0
- package/src/pyth/types.ts +4453 -0
- package/src/pyth/utils.ts +13 -0
- package/src/slot/SlotSubscriber.ts +108 -0
- package/src/slot/SlothashSubscriber.ts +126 -0
- package/src/swap/UnifiedSwapClient.ts +315 -0
- package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +95 -0
- package/src/swift/index.ts +10 -0
- package/src/swift/signedMsgUserAccountSubscriber.ts +241 -0
- package/src/swift/swiftOrderSubscriber.ts +347 -0
- package/src/testClient.ts +42 -0
- package/src/titan/titanClient.ts +438 -0
- package/src/token/index.ts +13 -0
- package/src/tokenFaucet.ts +274 -0
- package/src/tx/baseTxSender.ts +471 -0
- package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +19 -0
- package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +90 -0
- package/src/tx/blockhashFetcher/types.ts +5 -0
- package/src/tx/fastSingleTxSender.ts +142 -0
- package/src/tx/forwardOnlyTxSender.ts +145 -0
- package/src/tx/priorityFeeCalculator.ts +117 -0
- package/src/tx/reportTransactionError.ts +159 -0
- package/src/tx/retryTxSender.ts +135 -0
- package/src/tx/txHandler.ts +853 -0
- package/src/tx/txParamProcessor.ts +163 -0
- package/src/tx/types.ts +71 -0
- package/src/tx/utils.ts +107 -0
- package/src/tx/whileValidTxSender.ts +266 -0
- package/src/types.ts +1793 -0
- package/src/user.ts +4487 -0
- package/src/userConfig.ts +37 -0
- package/src/userMap/PollingSubscription.ts +47 -0
- package/src/userMap/WebsocketSubscription.ts +84 -0
- package/src/userMap/grpcSubscription.ts +85 -0
- package/src/userMap/referrerMap.ts +267 -0
- package/src/userMap/revenueShareEscrowMap.ts +310 -0
- package/src/userMap/userMap.ts +683 -0
- package/src/userMap/userMapConfig.ts +66 -0
- package/src/userMap/userStatsMap.ts +358 -0
- package/src/userName.ts +21 -0
- package/src/userStats.ts +117 -0
- package/src/userStatsConfig.ts +32 -0
- package/src/util/TransactionConfirmationManager.ts +292 -0
- package/src/util/chainClock.ts +41 -0
- package/src/util/computeUnits.ts +65 -0
- package/src/util/digest.ts +16 -0
- package/src/util/ed25519Utils.ts +85 -0
- package/src/util/promiseTimeout.ts +14 -0
- package/src/util/tps.ts +27 -0
- package/src/velocityClient.ts +11364 -0
- package/src/velocityClientConfig.ts +144 -0
- package/src/wallet.ts +54 -0
- package/tests/DriftCore/decode.test.ts +16 -0
- package/tests/DriftCore/fill_trigger.test.ts +73 -0
- package/tests/DriftCore/instructions.test.ts +46 -0
- package/tests/DriftCore/pdas.test.ts +28 -0
- package/tests/DriftCore/perp_orders.test.ts +205 -0
- package/tests/DriftCore/remainingAccounts.test.ts +73 -0
- package/tests/DriftCore/settlement_liquidation.test.ts +69 -0
- package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +203 -0
- package/tests/amm/test.ts +2095 -0
- package/tests/auctions/test.ts +81 -0
- package/tests/bn/test.ts +355 -0
- package/tests/ci/verifyConstants.ts +396 -0
- package/tests/decode/phoenix.ts +71 -0
- package/tests/decode/test.ts +262 -0
- package/tests/decode/userAccountBufferStrings.ts +102 -0
- package/tests/dlob/helpers.ts +740 -0
- package/tests/dlob/test.ts +6920 -0
- package/tests/events/parseLogsForCuUsage.ts +139 -0
- package/tests/insurance/test.ts +40 -0
- package/tests/spot/test.ts +226 -0
- package/tests/tx/TransactionConfirmationManager.test.ts +305 -0
- package/tests/tx/cachedBlockhashFetcher.test.ts +96 -0
- package/tests/tx/priorityFeeCalculator.ts +77 -0
- package/tests/tx/priorityFeeStrategy.ts +95 -0
- package/tests/user/getMarginCalculation.ts +361 -0
- package/tests/user/helpers.ts +185 -0
- package/tests/user/liquidations.ts +129 -0
- package/tests/user/marginCalculations.test.ts +321 -0
- package/tests/user/test.ts +826 -0
- package/tsconfig.browser.json +16 -0
- package/tsconfig.json +17 -0
package/src/user.ts
ADDED
|
@@ -0,0 +1,4487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User — read-oriented abstraction over the on-chain `User` account.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Margin and free-collateral calculations (mirrors `programs/drift/src/math/margin.rs`).
|
|
6
|
+
* - Position accessors: perp positions, spot positions, unrealized PnL, leverage.
|
|
7
|
+
* - Open order queries and filtering.
|
|
8
|
+
* - Health factor and liquidation threshold checks.
|
|
9
|
+
* - Subscribes to and caches the latest `User` account state from chain.
|
|
10
|
+
*
|
|
11
|
+
* To send instructions (deposit, place order, etc.) use {@link VelocityClient}.
|
|
12
|
+
* For referral/volume stats see {@link UserStats} (userStats.ts).
|
|
13
|
+
*/
|
|
14
|
+
import { PublicKey } from '@solana/web3.js';
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
17
|
+
import { VelocityClient } from './velocityClient';
|
|
18
|
+
import {
|
|
19
|
+
HealthComponent,
|
|
20
|
+
HealthComponents,
|
|
21
|
+
isVariant,
|
|
22
|
+
MarginCategory,
|
|
23
|
+
Order,
|
|
24
|
+
PerpMarketAccount,
|
|
25
|
+
PerpPosition,
|
|
26
|
+
ReferrerStatus,
|
|
27
|
+
SpotPosition,
|
|
28
|
+
UserAccount,
|
|
29
|
+
UserStatus,
|
|
30
|
+
UserStatsAccount,
|
|
31
|
+
AccountLiquidatableStatus,
|
|
32
|
+
} from './types';
|
|
33
|
+
import {
|
|
34
|
+
calculateEntryPrice,
|
|
35
|
+
calculateUnsettledFundingPnl,
|
|
36
|
+
positionIsAvailable,
|
|
37
|
+
} from './math/position';
|
|
38
|
+
import {
|
|
39
|
+
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
40
|
+
BASE_PRECISION,
|
|
41
|
+
BN_MAX,
|
|
42
|
+
DUST_POSITION_SIZE,
|
|
43
|
+
FIVE_MINUTE,
|
|
44
|
+
MARGIN_PRECISION,
|
|
45
|
+
OPEN_ORDER_MARGIN_REQUIREMENT,
|
|
46
|
+
PRICE_PRECISION,
|
|
47
|
+
QUOTE_PRECISION,
|
|
48
|
+
QUOTE_PRECISION_EXP,
|
|
49
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
50
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
51
|
+
TEN_THOUSAND,
|
|
52
|
+
TWO,
|
|
53
|
+
ZERO,
|
|
54
|
+
ACCOUNT_AGE_DELETION_CUTOFF_SECONDS,
|
|
55
|
+
} from './constants/numericConstants';
|
|
56
|
+
import {
|
|
57
|
+
DataAndSlot,
|
|
58
|
+
UserAccountEvents,
|
|
59
|
+
UserAccountSubscriber,
|
|
60
|
+
} from './accounts/types';
|
|
61
|
+
import { BigNum } from './factory/bigNum';
|
|
62
|
+
import { BN } from './isomorphic/anchor';
|
|
63
|
+
import { calculateBaseAssetValue, calculatePositionPNL } from './math/position';
|
|
64
|
+
import {
|
|
65
|
+
calculateMarketMarginRatio,
|
|
66
|
+
calculateReservePrice,
|
|
67
|
+
calculateUnrealizedAssetWeight,
|
|
68
|
+
} from './math/market';
|
|
69
|
+
import {
|
|
70
|
+
calculatePerpLiabilityValue,
|
|
71
|
+
calculateWorstCasePerpLiabilityValue,
|
|
72
|
+
} from './math/margin';
|
|
73
|
+
import { calculateSpotMarketMarginRatio } from './math/spotMarket';
|
|
74
|
+
import { divCeil, sigNum } from './math/utils';
|
|
75
|
+
import {
|
|
76
|
+
getBalance,
|
|
77
|
+
getSignedTokenAmount,
|
|
78
|
+
getStrictTokenValue,
|
|
79
|
+
getTokenValue,
|
|
80
|
+
} from './math/spotBalance';
|
|
81
|
+
import { getUser30dRollingVolumeEstimate } from './math/trade';
|
|
82
|
+
import {
|
|
83
|
+
MarketType,
|
|
84
|
+
PositionDirection,
|
|
85
|
+
PositionFlag,
|
|
86
|
+
SpotBalanceType,
|
|
87
|
+
SpotMarketAccount,
|
|
88
|
+
} from './types';
|
|
89
|
+
import { standardizeBaseAssetAmount } from './math/orders';
|
|
90
|
+
import { WebSocketProgramUserAccountSubscriber } from './accounts/websocketProgramUserAccountSubscriber';
|
|
91
|
+
import {
|
|
92
|
+
calculateAssetWeight,
|
|
93
|
+
calculateLiabilityWeight,
|
|
94
|
+
calculateWithdrawLimit,
|
|
95
|
+
getSpotAssetValue,
|
|
96
|
+
getSpotLiabilityValue,
|
|
97
|
+
getTokenAmount,
|
|
98
|
+
} from './math/spotBalance';
|
|
99
|
+
import {
|
|
100
|
+
calculateBaseAssetValueWithOracle,
|
|
101
|
+
calculateCollateralDepositRequiredForTrade,
|
|
102
|
+
calculateMarginUSDCRequiredForTrade,
|
|
103
|
+
calculateWorstCaseBaseAssetAmount,
|
|
104
|
+
} from './math/margin';
|
|
105
|
+
import { MMOraclePriceData, OraclePriceData } from './oracles/types';
|
|
106
|
+
import { UserConfig } from './userConfig';
|
|
107
|
+
import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
|
|
108
|
+
import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
|
|
109
|
+
import {
|
|
110
|
+
calculateWeightedTokenValue,
|
|
111
|
+
getWorstCaseTokenAmounts,
|
|
112
|
+
isSpotPositionAvailable,
|
|
113
|
+
} from './math/spotPosition';
|
|
114
|
+
import {
|
|
115
|
+
calculateLiveOracleTwap,
|
|
116
|
+
getMultipleBetweenOracleSources,
|
|
117
|
+
} from './math/oracles';
|
|
118
|
+
import { getPerpMarketTierNumber, getSpotMarketTierNumber } from './math/tiers';
|
|
119
|
+
import { StrictOraclePrice } from './oracles/strictOraclePrice';
|
|
120
|
+
|
|
121
|
+
import { grpcUserAccountSubscriber } from './accounts/grpcUserAccountSubscriber';
|
|
122
|
+
import {
|
|
123
|
+
IsolatedMarginCalculation,
|
|
124
|
+
MarginCalculation,
|
|
125
|
+
MarginContext,
|
|
126
|
+
} from './marginCalculation';
|
|
127
|
+
|
|
128
|
+
export type MarginType = 'Cross' | 'Isolated';
|
|
129
|
+
|
|
130
|
+
export class User {
|
|
131
|
+
driftClient: VelocityClient;
|
|
132
|
+
userAccountPublicKey: PublicKey;
|
|
133
|
+
accountSubscriber: UserAccountSubscriber;
|
|
134
|
+
_isSubscribed = false;
|
|
135
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
136
|
+
|
|
137
|
+
public get isSubscribed() {
|
|
138
|
+
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public set isSubscribed(val: boolean) {
|
|
142
|
+
this._isSubscribed = val;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public constructor(config: UserConfig) {
|
|
146
|
+
this.driftClient = config.driftClient;
|
|
147
|
+
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
148
|
+
if (config.accountSubscription?.type === 'polling') {
|
|
149
|
+
this.accountSubscriber = new PollingUserAccountSubscriber(
|
|
150
|
+
config.driftClient.connection,
|
|
151
|
+
config.userAccountPublicKey,
|
|
152
|
+
config.accountSubscription.accountLoader,
|
|
153
|
+
(
|
|
154
|
+
this.driftClient.program.account as any
|
|
155
|
+
).user.coder.accounts.decodeUnchecked.bind(
|
|
156
|
+
(this.driftClient.program.account as any).user.coder.accounts
|
|
157
|
+
)
|
|
158
|
+
);
|
|
159
|
+
} else if (config.accountSubscription?.type === 'custom') {
|
|
160
|
+
this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
|
|
161
|
+
} else if (config.accountSubscription?.type === 'grpc') {
|
|
162
|
+
if (config.accountSubscription.grpcMultiUserAccountSubscriber) {
|
|
163
|
+
this.accountSubscriber =
|
|
164
|
+
config.accountSubscription.grpcMultiUserAccountSubscriber.forUser(
|
|
165
|
+
config.userAccountPublicKey
|
|
166
|
+
);
|
|
167
|
+
} else {
|
|
168
|
+
this.accountSubscriber = new grpcUserAccountSubscriber(
|
|
169
|
+
config.accountSubscription.grpcConfigs,
|
|
170
|
+
config.driftClient.program,
|
|
171
|
+
config.userAccountPublicKey,
|
|
172
|
+
{
|
|
173
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
174
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
if (
|
|
180
|
+
config.accountSubscription?.type === 'websocket' &&
|
|
181
|
+
config.accountSubscription?.programUserAccountSubscriber
|
|
182
|
+
) {
|
|
183
|
+
this.accountSubscriber = new WebSocketProgramUserAccountSubscriber(
|
|
184
|
+
config.driftClient.program,
|
|
185
|
+
config.userAccountPublicKey,
|
|
186
|
+
config.accountSubscription.programUserAccountSubscriber
|
|
187
|
+
);
|
|
188
|
+
} else {
|
|
189
|
+
this.accountSubscriber = new WebSocketUserAccountSubscriber(
|
|
190
|
+
config.driftClient.program,
|
|
191
|
+
config.userAccountPublicKey,
|
|
192
|
+
{
|
|
193
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
194
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
195
|
+
},
|
|
196
|
+
config.accountSubscription?.commitment
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Subscribe to User state accounts
|
|
205
|
+
* @returns SusbcriptionSuccess result
|
|
206
|
+
*/
|
|
207
|
+
public async subscribe(userAccount?: UserAccount): Promise<boolean> {
|
|
208
|
+
this.isSubscribed = await this.accountSubscriber.subscribe(userAccount);
|
|
209
|
+
return this.isSubscribed;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Forces the accountSubscriber to fetch account updates from rpc
|
|
214
|
+
*/
|
|
215
|
+
public async fetchAccounts(): Promise<void> {
|
|
216
|
+
await this.accountSubscriber.fetch();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public async unsubscribe(): Promise<void> {
|
|
220
|
+
this.eventEmitter.removeAllListeners();
|
|
221
|
+
await this.accountSubscriber.unsubscribe();
|
|
222
|
+
this.isSubscribed = false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public getUserAccount(): UserAccount {
|
|
226
|
+
return this.accountSubscriber.getUserAccountAndSlot().data;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public async forceGetUserAccount(): Promise<UserAccount> {
|
|
230
|
+
await this.fetchAccounts();
|
|
231
|
+
return this.accountSubscriber.getUserAccountAndSlot().data;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
public getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined {
|
|
235
|
+
return this.accountSubscriber.getUserAccountAndSlot();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public getPerpPositionForUserAccount(
|
|
239
|
+
userAccount: UserAccount,
|
|
240
|
+
marketIndex: number
|
|
241
|
+
): PerpPosition | undefined {
|
|
242
|
+
return this.getActivePerpPositionsForUserAccount(userAccount).find(
|
|
243
|
+
(position) => position.marketIndex === marketIndex
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Gets the user's current position for a given perp market. If the user has no position returns undefined
|
|
249
|
+
* @param marketIndex
|
|
250
|
+
* @returns userPerpPosition
|
|
251
|
+
*/
|
|
252
|
+
public getPerpPosition(marketIndex: number): PerpPosition | undefined {
|
|
253
|
+
const userAccount = this.getUserAccount();
|
|
254
|
+
return this.getPerpPositionForUserAccount(userAccount, marketIndex);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public getPerpPositionOrEmpty(marketIndex: number): PerpPosition {
|
|
258
|
+
const userAccount = this.getUserAccount();
|
|
259
|
+
return (
|
|
260
|
+
this.getPerpPositionForUserAccount(userAccount, marketIndex) ??
|
|
261
|
+
this.getEmptyPosition(marketIndex)
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public getPerpPositionAndSlot(
|
|
266
|
+
marketIndex: number
|
|
267
|
+
): DataAndSlot<PerpPosition | undefined> {
|
|
268
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
269
|
+
const perpPosition = this.getPerpPositionForUserAccount(
|
|
270
|
+
userAccount.data,
|
|
271
|
+
marketIndex
|
|
272
|
+
);
|
|
273
|
+
return {
|
|
274
|
+
data: perpPosition,
|
|
275
|
+
slot: userAccount.slot,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
public getSpotPositionForUserAccount(
|
|
280
|
+
userAccount: UserAccount,
|
|
281
|
+
marketIndex: number
|
|
282
|
+
): SpotPosition | undefined {
|
|
283
|
+
return userAccount.spotPositions.find(
|
|
284
|
+
(position) => position.marketIndex === marketIndex
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Gets the user's current position for a given spot market. If the user has no position returns undefined
|
|
290
|
+
* @param marketIndex
|
|
291
|
+
* @returns userSpotPosition
|
|
292
|
+
*/
|
|
293
|
+
public getSpotPosition(marketIndex: number): SpotPosition | undefined {
|
|
294
|
+
const userAccount = this.getUserAccount();
|
|
295
|
+
return this.getSpotPositionForUserAccount(userAccount, marketIndex);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public getSpotPositionAndSlot(
|
|
299
|
+
marketIndex: number
|
|
300
|
+
): DataAndSlot<SpotPosition | undefined> {
|
|
301
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
302
|
+
const spotPosition = this.getSpotPositionForUserAccount(
|
|
303
|
+
userAccount.data,
|
|
304
|
+
marketIndex
|
|
305
|
+
);
|
|
306
|
+
return {
|
|
307
|
+
data: spotPosition,
|
|
308
|
+
slot: userAccount.slot,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
getEmptySpotPosition(marketIndex: number): SpotPosition {
|
|
313
|
+
return {
|
|
314
|
+
marketIndex,
|
|
315
|
+
scaledBalance: ZERO,
|
|
316
|
+
balanceType: SpotBalanceType.DEPOSIT,
|
|
317
|
+
cumulativeDeposits: ZERO,
|
|
318
|
+
openAsks: ZERO,
|
|
319
|
+
openBids: ZERO,
|
|
320
|
+
openOrders: 0,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
|
|
326
|
+
* Positive if it is a deposit, negative if it is a borrow.
|
|
327
|
+
*
|
|
328
|
+
* @param marketIndex
|
|
329
|
+
*/
|
|
330
|
+
public getTokenAmount(marketIndex: number): BN {
|
|
331
|
+
const spotPosition = this.getSpotPosition(marketIndex);
|
|
332
|
+
if (spotPosition === undefined) {
|
|
333
|
+
return ZERO;
|
|
334
|
+
}
|
|
335
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
336
|
+
return getSignedTokenAmount(
|
|
337
|
+
getTokenAmount(
|
|
338
|
+
spotPosition.scaledBalance,
|
|
339
|
+
spotMarket,
|
|
340
|
+
spotPosition.balanceType
|
|
341
|
+
),
|
|
342
|
+
spotPosition.balanceType
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public getEmptyPosition(marketIndex: number): PerpPosition {
|
|
347
|
+
return {
|
|
348
|
+
baseAssetAmount: ZERO,
|
|
349
|
+
remainderBaseAssetAmount: 0,
|
|
350
|
+
lastCumulativeFundingRate: ZERO,
|
|
351
|
+
marketIndex,
|
|
352
|
+
quoteAssetAmount: ZERO,
|
|
353
|
+
quoteEntryAmount: ZERO,
|
|
354
|
+
quoteBreakEvenAmount: ZERO,
|
|
355
|
+
openOrders: 0,
|
|
356
|
+
openBids: ZERO,
|
|
357
|
+
openAsks: ZERO,
|
|
358
|
+
settledPnl: ZERO,
|
|
359
|
+
maxMarginRatio: 0,
|
|
360
|
+
isolatedPositionScaledBalance: ZERO,
|
|
361
|
+
positionFlag: 0,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public isPositionEmpty(position: PerpPosition): boolean {
|
|
366
|
+
return position.baseAssetAmount.eq(ZERO) && position.openOrders === 0;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
public getIsolatePerpPositionTokenAmount(perpMarketIndex: number): BN {
|
|
370
|
+
const perpPosition = this.getPerpPosition(perpMarketIndex);
|
|
371
|
+
if (!perpPosition) return ZERO;
|
|
372
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(perpMarketIndex);
|
|
373
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(
|
|
374
|
+
perpMarket.quoteSpotMarketIndex
|
|
375
|
+
);
|
|
376
|
+
if (perpPosition === undefined) {
|
|
377
|
+
return ZERO;
|
|
378
|
+
}
|
|
379
|
+
return getTokenAmount(
|
|
380
|
+
perpPosition.isolatedPositionScaledBalance ?? ZERO, //TODO remove ? later
|
|
381
|
+
spotMarket,
|
|
382
|
+
SpotBalanceType.DEPOSIT
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Returns the total USD value of deposits across all isolated perp positions.
|
|
388
|
+
*/
|
|
389
|
+
public getTotalIsolatedPositionDeposits(): BN {
|
|
390
|
+
return this.getActivePerpPositions().reduce((total, perpPosition) => {
|
|
391
|
+
if (!perpPosition.isolatedPositionScaledBalance?.gt(ZERO)) {
|
|
392
|
+
return total;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
396
|
+
perpPosition.marketIndex
|
|
397
|
+
);
|
|
398
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
399
|
+
perpMarket.quoteSpotMarketIndex
|
|
400
|
+
);
|
|
401
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(
|
|
402
|
+
perpMarket.quoteSpotMarketIndex
|
|
403
|
+
);
|
|
404
|
+
const strictOracle = new StrictOraclePrice(
|
|
405
|
+
quoteOraclePriceData.price,
|
|
406
|
+
quoteOraclePriceData.twap
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
const tokenAmount = getTokenAmount(
|
|
410
|
+
perpPosition.isolatedPositionScaledBalance,
|
|
411
|
+
quoteSpotMarket,
|
|
412
|
+
SpotBalanceType.DEPOSIT
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
return total.add(
|
|
416
|
+
getStrictTokenValue(tokenAmount, quoteSpotMarket.decimals, strictOracle)
|
|
417
|
+
);
|
|
418
|
+
}, ZERO);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
public getClonedPosition(position: PerpPosition): PerpPosition {
|
|
422
|
+
const clonedPosition = Object.assign({}, position);
|
|
423
|
+
return clonedPosition;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
public getOrderForUserAccount(
|
|
427
|
+
userAccount: UserAccount,
|
|
428
|
+
orderId: number
|
|
429
|
+
): Order | undefined {
|
|
430
|
+
return userAccount.orders.find((order) => order.orderId === orderId);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @param orderId
|
|
435
|
+
* @returns Order
|
|
436
|
+
*/
|
|
437
|
+
public getOrder(orderId: number): Order | undefined {
|
|
438
|
+
const userAccount = this.getUserAccount();
|
|
439
|
+
return this.getOrderForUserAccount(userAccount, orderId);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
public getOrderAndSlot(orderId: number): DataAndSlot<Order | undefined> {
|
|
443
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
444
|
+
const order = this.getOrderForUserAccount(userAccount.data, orderId);
|
|
445
|
+
return {
|
|
446
|
+
data: order,
|
|
447
|
+
slot: userAccount.slot,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public getOrderByUserIdForUserAccount(
|
|
452
|
+
userAccount: UserAccount,
|
|
453
|
+
userOrderId: number
|
|
454
|
+
): Order | undefined {
|
|
455
|
+
return userAccount.orders.find(
|
|
456
|
+
(order) => order.userOrderId === userOrderId
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* @param userOrderId
|
|
462
|
+
* @returns Order
|
|
463
|
+
*/
|
|
464
|
+
public getOrderByUserOrderId(userOrderId: number): Order | undefined {
|
|
465
|
+
const userAccount = this.getUserAccount();
|
|
466
|
+
return this.getOrderByUserIdForUserAccount(userAccount, userOrderId);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
public getOrderByUserOrderIdAndSlot(
|
|
470
|
+
userOrderId: number
|
|
471
|
+
): DataAndSlot<Order | undefined> {
|
|
472
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
473
|
+
const order = this.getOrderByUserIdForUserAccount(
|
|
474
|
+
userAccount.data,
|
|
475
|
+
userOrderId
|
|
476
|
+
);
|
|
477
|
+
return {
|
|
478
|
+
data: order,
|
|
479
|
+
slot: userAccount.slot,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
public getOpenOrdersForUserAccount(userAccount?: UserAccount): Order[] {
|
|
484
|
+
return userAccount?.orders.filter((order) =>
|
|
485
|
+
isVariant(order.status, 'open')
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
public getOpenOrders(): Order[] {
|
|
490
|
+
const userAccount = this.getUserAccount();
|
|
491
|
+
return this.getOpenOrdersForUserAccount(userAccount);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public getOpenOrdersAndSlot(): DataAndSlot<Order[]> {
|
|
495
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
496
|
+
const openOrders = this.getOpenOrdersForUserAccount(userAccount.data);
|
|
497
|
+
return {
|
|
498
|
+
data: openOrders,
|
|
499
|
+
slot: userAccount.slot,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
public getUserAccountPublicKey(): PublicKey {
|
|
504
|
+
return this.userAccountPublicKey;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
public async exists(): Promise<boolean> {
|
|
508
|
+
const userAccountRPCResponse =
|
|
509
|
+
await this.driftClient.connection.getParsedAccountInfo(
|
|
510
|
+
this.userAccountPublicKey
|
|
511
|
+
);
|
|
512
|
+
return userAccountRPCResponse.value !== null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* calculates the total open bids/asks in a perp market (including lps)
|
|
517
|
+
* @returns : open bids
|
|
518
|
+
* @returns : open asks
|
|
519
|
+
*/
|
|
520
|
+
public getPerpBidAsks(marketIndex: number): [BN, BN] {
|
|
521
|
+
const position = this.getPerpPosition(marketIndex);
|
|
522
|
+
|
|
523
|
+
const totalOpenBids = position.openBids;
|
|
524
|
+
const totalOpenAsks = position.openAsks;
|
|
525
|
+
|
|
526
|
+
return [totalOpenBids, totalOpenAsks];
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* calculates Buying Power = free collateral / initial margin ratio
|
|
531
|
+
* @returns : Precision QUOTE_PRECISION
|
|
532
|
+
*/
|
|
533
|
+
public getPerpBuyingPower(
|
|
534
|
+
marketIndex: number,
|
|
535
|
+
collateralBuffer = ZERO,
|
|
536
|
+
maxMarginRatio = undefined,
|
|
537
|
+
positionType: 'isolated' | 'cross' = 'cross'
|
|
538
|
+
): BN {
|
|
539
|
+
const perpPosition = this.getPerpPositionOrEmpty(marketIndex);
|
|
540
|
+
|
|
541
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
542
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
|
|
543
|
+
const worstCaseBaseAssetAmount = perpPosition
|
|
544
|
+
? calculateWorstCaseBaseAssetAmount(
|
|
545
|
+
perpPosition,
|
|
546
|
+
perpMarket,
|
|
547
|
+
oraclePriceData.price
|
|
548
|
+
)
|
|
549
|
+
: ZERO;
|
|
550
|
+
|
|
551
|
+
// if position is isolated, we always add on available quote from the cross account
|
|
552
|
+
let freeCollateral: BN = ZERO;
|
|
553
|
+
if (positionType === 'isolated') {
|
|
554
|
+
const {
|
|
555
|
+
totalAssetValue: quoteSpotMarketAssetValue,
|
|
556
|
+
totalLiabilityValue: quoteSpotMarketLiabilityValue,
|
|
557
|
+
} = this.getSpotMarketAssetAndLiabilityValue(
|
|
558
|
+
perpMarket.quoteSpotMarketIndex,
|
|
559
|
+
'Initial',
|
|
560
|
+
undefined,
|
|
561
|
+
undefined,
|
|
562
|
+
true
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
const usdcAvailableForIsolatedMargin = quoteSpotMarketAssetValue.sub(
|
|
566
|
+
quoteSpotMarketLiabilityValue
|
|
567
|
+
);
|
|
568
|
+
const generalFreeCollateral = this.getFreeCollateral(
|
|
569
|
+
'Initial',
|
|
570
|
+
undefined
|
|
571
|
+
);
|
|
572
|
+
freeCollateral = BN.min(
|
|
573
|
+
usdcAvailableForIsolatedMargin,
|
|
574
|
+
generalFreeCollateral
|
|
575
|
+
).sub(collateralBuffer);
|
|
576
|
+
} else {
|
|
577
|
+
// free collateral from the cross account only
|
|
578
|
+
freeCollateral = this.getFreeCollateral('Initial', undefined).sub(
|
|
579
|
+
collateralBuffer
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
584
|
+
marketIndex,
|
|
585
|
+
freeCollateral,
|
|
586
|
+
worstCaseBaseAssetAmount,
|
|
587
|
+
maxMarginRatio || perpPosition.maxMarginRatio
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
592
|
+
marketIndex: number,
|
|
593
|
+
freeCollateral: BN,
|
|
594
|
+
baseAssetAmount: BN,
|
|
595
|
+
perpMarketMaxMarginRatio = undefined
|
|
596
|
+
): BN {
|
|
597
|
+
const maxMarginRatio = Math.max(
|
|
598
|
+
perpMarketMaxMarginRatio,
|
|
599
|
+
this.getUserAccount().maxMarginRatio
|
|
600
|
+
);
|
|
601
|
+
const marginRatio = calculateMarketMarginRatio(
|
|
602
|
+
this.driftClient.getPerpMarketAccount(marketIndex),
|
|
603
|
+
baseAssetAmount,
|
|
604
|
+
'Initial',
|
|
605
|
+
maxMarginRatio
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
return freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio));
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
613
|
+
* @returns : Precision QUOTE_PRECISION
|
|
614
|
+
*/
|
|
615
|
+
public getFreeCollateral(
|
|
616
|
+
marginCategory: MarginCategory = 'Initial',
|
|
617
|
+
perpMarketIndex?: number
|
|
618
|
+
): BN {
|
|
619
|
+
const calc = this.getMarginCalculation(marginCategory, {
|
|
620
|
+
strict: marginCategory === 'Initial',
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
if (perpMarketIndex !== undefined) {
|
|
624
|
+
// getIsolatedFreeCollateral will throw if no existing isolated position but we are fetching for potential new position, so we wrap in a try/catch
|
|
625
|
+
try {
|
|
626
|
+
return calc.getIsolatedFreeCollateral(perpMarketIndex);
|
|
627
|
+
} catch (error) {
|
|
628
|
+
return ZERO;
|
|
629
|
+
}
|
|
630
|
+
} else {
|
|
631
|
+
return calc.getCrossFreeCollateral();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* @deprecated Use the overload that includes { marginType, perpMarketIndex }
|
|
637
|
+
*/
|
|
638
|
+
public getMarginRequirement(
|
|
639
|
+
marginCategory: MarginCategory,
|
|
640
|
+
liquidationBuffer?: BN,
|
|
641
|
+
strict?: boolean,
|
|
642
|
+
includeOpenOrders?: boolean
|
|
643
|
+
): BN;
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Calculates the margin requirement based on the specified parameters.
|
|
647
|
+
*
|
|
648
|
+
* @param marginCategory - The category of margin to calculate ('Initial' or 'Maintenance').
|
|
649
|
+
* @param liquidationBuffer - Optional buffer amount to consider during liquidation scenarios.
|
|
650
|
+
* @param strict - Optional flag to enforce strict margin calculations.
|
|
651
|
+
* @param includeOpenOrders - Optional flag to include open orders in the margin calculation.
|
|
652
|
+
* @param perpMarketIndex - Optional index of the perpetual market. Required if marginType is 'Isolated'.
|
|
653
|
+
*
|
|
654
|
+
* @returns The calculated margin requirement as a BN (BigNumber).
|
|
655
|
+
*/
|
|
656
|
+
public getMarginRequirement(
|
|
657
|
+
marginCategory: MarginCategory,
|
|
658
|
+
liquidationBuffer?: BN,
|
|
659
|
+
strict?: boolean,
|
|
660
|
+
includeOpenOrders?: boolean,
|
|
661
|
+
perpMarketIndex?: number
|
|
662
|
+
): BN;
|
|
663
|
+
|
|
664
|
+
public getMarginRequirement(
|
|
665
|
+
marginCategory: MarginCategory,
|
|
666
|
+
liquidationBuffer?: BN,
|
|
667
|
+
strict?: boolean,
|
|
668
|
+
includeOpenOrders?: boolean,
|
|
669
|
+
perpMarketIndex?: number
|
|
670
|
+
): BN {
|
|
671
|
+
const liquidationBufferMap = new Map();
|
|
672
|
+
if (liquidationBuffer && perpMarketIndex !== undefined) {
|
|
673
|
+
liquidationBufferMap.set(perpMarketIndex, liquidationBuffer);
|
|
674
|
+
} else if (liquidationBuffer) {
|
|
675
|
+
liquidationBufferMap.set('cross', liquidationBuffer);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const marginCalc = this.getMarginCalculation(marginCategory, {
|
|
679
|
+
strict,
|
|
680
|
+
includeOpenOrders,
|
|
681
|
+
liquidationBufferMap,
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// If perpMarketIndex is provided, compute only for that market index
|
|
685
|
+
if (perpMarketIndex !== undefined) {
|
|
686
|
+
const isolatedMarginCalculation =
|
|
687
|
+
marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
688
|
+
if (!isolatedMarginCalculation) return ZERO;
|
|
689
|
+
const { marginRequirement, marginRequirementPlusBuffer } =
|
|
690
|
+
isolatedMarginCalculation;
|
|
691
|
+
|
|
692
|
+
if (liquidationBuffer?.gt(ZERO)) {
|
|
693
|
+
return marginRequirementPlusBuffer;
|
|
694
|
+
}
|
|
695
|
+
return marginRequirement;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Default: Cross margin requirement
|
|
699
|
+
if (liquidationBuffer?.gt(ZERO)) {
|
|
700
|
+
return marginCalc.marginRequirementPlusBuffer;
|
|
701
|
+
}
|
|
702
|
+
return marginCalc.marginRequirement;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
|
|
707
|
+
*/
|
|
708
|
+
public getInitialMarginRequirement(perpMarketIndex?: number): BN {
|
|
709
|
+
return this.getMarginRequirement(
|
|
710
|
+
'Initial',
|
|
711
|
+
undefined,
|
|
712
|
+
true,
|
|
713
|
+
undefined,
|
|
714
|
+
perpMarketIndex
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
720
|
+
*/
|
|
721
|
+
public getMaintenanceMarginRequirement(
|
|
722
|
+
liquidationBuffer?: BN,
|
|
723
|
+
perpMarketIndex?: number
|
|
724
|
+
): BN {
|
|
725
|
+
return this.getMarginRequirement(
|
|
726
|
+
'Maintenance',
|
|
727
|
+
liquidationBuffer,
|
|
728
|
+
false, // strict default
|
|
729
|
+
true, // includeOpenOrders default
|
|
730
|
+
perpMarketIndex
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
public getActivePerpPositionsForUserAccount(
|
|
735
|
+
userAccount: UserAccount
|
|
736
|
+
): PerpPosition[] {
|
|
737
|
+
return userAccount.perpPositions.filter(
|
|
738
|
+
(pos) =>
|
|
739
|
+
!pos.baseAssetAmount.eq(ZERO) ||
|
|
740
|
+
!pos.quoteAssetAmount.eq(ZERO) ||
|
|
741
|
+
!(pos.openOrders == 0) ||
|
|
742
|
+
pos.isolatedPositionScaledBalance?.gt(ZERO)
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
public getActivePerpPositions(): PerpPosition[] {
|
|
747
|
+
const userAccount = this.getUserAccount();
|
|
748
|
+
return this.getActivePerpPositionsForUserAccount(userAccount);
|
|
749
|
+
}
|
|
750
|
+
public getActivePerpPositionsAndSlot(): DataAndSlot<PerpPosition[]> {
|
|
751
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
752
|
+
const positions = this.getActivePerpPositionsForUserAccount(
|
|
753
|
+
userAccount.data
|
|
754
|
+
);
|
|
755
|
+
return {
|
|
756
|
+
data: positions,
|
|
757
|
+
slot: userAccount.slot,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
public getActiveSpotPositionsForUserAccount(
|
|
762
|
+
userAccount: UserAccount
|
|
763
|
+
): SpotPosition[] {
|
|
764
|
+
return userAccount.spotPositions.filter(
|
|
765
|
+
(pos) => !isSpotPositionAvailable(pos)
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
public getActiveSpotPositions(): SpotPosition[] {
|
|
770
|
+
const userAccount = this.getUserAccount();
|
|
771
|
+
return this.getActiveSpotPositionsForUserAccount(userAccount);
|
|
772
|
+
}
|
|
773
|
+
public getActiveSpotPositionsAndSlot(): DataAndSlot<SpotPosition[]> {
|
|
774
|
+
const userAccount = this.getUserAccountAndSlot();
|
|
775
|
+
const positions = this.getActiveSpotPositionsForUserAccount(
|
|
776
|
+
userAccount.data
|
|
777
|
+
);
|
|
778
|
+
return {
|
|
779
|
+
data: positions,
|
|
780
|
+
slot: userAccount.slot,
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* calculates unrealized position price pnl
|
|
786
|
+
* @returns : Precision QUOTE_PRECISION
|
|
787
|
+
*/
|
|
788
|
+
public getUnrealizedPNL(
|
|
789
|
+
withFunding?: boolean,
|
|
790
|
+
marketIndex?: number,
|
|
791
|
+
withWeightMarginCategory?: MarginCategory,
|
|
792
|
+
strict = false,
|
|
793
|
+
liquidationBuffer?: BN
|
|
794
|
+
): BN {
|
|
795
|
+
return this.getActivePerpPositions()
|
|
796
|
+
.filter((pos) =>
|
|
797
|
+
marketIndex !== undefined ? pos.marketIndex === marketIndex : true
|
|
798
|
+
)
|
|
799
|
+
.reduce((unrealizedPnl, perpPosition) => {
|
|
800
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
801
|
+
perpPosition.marketIndex
|
|
802
|
+
);
|
|
803
|
+
const oraclePriceData = this.getMMOracleDataForPerpMarket(
|
|
804
|
+
market.marketIndex
|
|
805
|
+
);
|
|
806
|
+
|
|
807
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
808
|
+
market.quoteSpotMarketIndex
|
|
809
|
+
);
|
|
810
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(
|
|
811
|
+
market.quoteSpotMarketIndex
|
|
812
|
+
);
|
|
813
|
+
|
|
814
|
+
let positionUnrealizedPnl = calculatePositionPNL(
|
|
815
|
+
market,
|
|
816
|
+
perpPosition,
|
|
817
|
+
withFunding,
|
|
818
|
+
oraclePriceData
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
let quotePrice;
|
|
822
|
+
if (strict && positionUnrealizedPnl.gt(ZERO)) {
|
|
823
|
+
quotePrice = BN.min(
|
|
824
|
+
quoteOraclePriceData.price,
|
|
825
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
826
|
+
);
|
|
827
|
+
} else if (strict && positionUnrealizedPnl.lt(ZERO)) {
|
|
828
|
+
quotePrice = BN.max(
|
|
829
|
+
quoteOraclePriceData.price,
|
|
830
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
831
|
+
);
|
|
832
|
+
} else {
|
|
833
|
+
quotePrice = quoteOraclePriceData.price;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
837
|
+
.mul(quotePrice)
|
|
838
|
+
.div(PRICE_PRECISION);
|
|
839
|
+
|
|
840
|
+
if (withWeightMarginCategory !== undefined) {
|
|
841
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
842
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
843
|
+
.mul(
|
|
844
|
+
calculateUnrealizedAssetWeight(
|
|
845
|
+
market,
|
|
846
|
+
quoteSpotMarket,
|
|
847
|
+
positionUnrealizedPnl,
|
|
848
|
+
withWeightMarginCategory,
|
|
849
|
+
oraclePriceData
|
|
850
|
+
)
|
|
851
|
+
)
|
|
852
|
+
.div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (liquidationBuffer && positionUnrealizedPnl.lt(ZERO)) {
|
|
856
|
+
positionUnrealizedPnl = positionUnrealizedPnl.add(
|
|
857
|
+
positionUnrealizedPnl.mul(liquidationBuffer).div(MARGIN_PRECISION)
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return unrealizedPnl.add(positionUnrealizedPnl);
|
|
863
|
+
}, ZERO);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* calculates unrealized funding payment pnl
|
|
868
|
+
* @returns : Precision QUOTE_PRECISION
|
|
869
|
+
*/
|
|
870
|
+
public getUnrealizedFundingPNL(marketIndex?: number): BN {
|
|
871
|
+
return this.getUserAccount()
|
|
872
|
+
.perpPositions.filter((pos) =>
|
|
873
|
+
marketIndex !== undefined ? pos.marketIndex === marketIndex : true
|
|
874
|
+
)
|
|
875
|
+
.reduce((pnl, perpPosition) => {
|
|
876
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
877
|
+
perpPosition.marketIndex
|
|
878
|
+
);
|
|
879
|
+
return pnl.add(calculateUnsettledFundingPnl(market, perpPosition));
|
|
880
|
+
}, ZERO);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
public getSpotMarketAssetAndLiabilityValue(
|
|
884
|
+
marketIndex?: number,
|
|
885
|
+
marginCategory?: MarginCategory,
|
|
886
|
+
liquidationBuffer?: BN,
|
|
887
|
+
includeOpenOrders?: boolean,
|
|
888
|
+
strict = false,
|
|
889
|
+
now?: BN
|
|
890
|
+
): { totalAssetValue: BN; totalLiabilityValue: BN } {
|
|
891
|
+
now = now || new BN(new Date().getTime() / 1000);
|
|
892
|
+
let netQuoteValue = ZERO;
|
|
893
|
+
let totalAssetValue = ZERO;
|
|
894
|
+
let totalLiabilityValue = ZERO;
|
|
895
|
+
for (const spotPosition of this.getUserAccount().spotPositions) {
|
|
896
|
+
const countForBase =
|
|
897
|
+
marketIndex === undefined || spotPosition.marketIndex === marketIndex;
|
|
898
|
+
|
|
899
|
+
const countForQuote =
|
|
900
|
+
marketIndex === undefined ||
|
|
901
|
+
marketIndex === QUOTE_SPOT_MARKET_INDEX ||
|
|
902
|
+
(includeOpenOrders && spotPosition.openOrders !== 0);
|
|
903
|
+
if (
|
|
904
|
+
isSpotPositionAvailable(spotPosition) ||
|
|
905
|
+
(!countForBase && !countForQuote)
|
|
906
|
+
) {
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
911
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
912
|
+
|
|
913
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
914
|
+
spotPosition.marketIndex
|
|
915
|
+
);
|
|
916
|
+
|
|
917
|
+
let twap5min;
|
|
918
|
+
if (strict) {
|
|
919
|
+
twap5min = calculateLiveOracleTwap(
|
|
920
|
+
spotMarketAccount.historicalOracleData,
|
|
921
|
+
oraclePriceData,
|
|
922
|
+
now,
|
|
923
|
+
FIVE_MINUTE // 5MIN
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
const strictOraclePrice = new StrictOraclePrice(
|
|
927
|
+
oraclePriceData.price,
|
|
928
|
+
twap5min
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
if (
|
|
932
|
+
spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX &&
|
|
933
|
+
countForQuote
|
|
934
|
+
) {
|
|
935
|
+
const tokenAmount = getSignedTokenAmount(
|
|
936
|
+
getTokenAmount(
|
|
937
|
+
spotPosition.scaledBalance,
|
|
938
|
+
spotMarketAccount,
|
|
939
|
+
spotPosition.balanceType
|
|
940
|
+
),
|
|
941
|
+
spotPosition.balanceType
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
945
|
+
const weightedTokenValue = this.getSpotLiabilityValue(
|
|
946
|
+
tokenAmount,
|
|
947
|
+
strictOraclePrice,
|
|
948
|
+
spotMarketAccount,
|
|
949
|
+
marginCategory,
|
|
950
|
+
liquidationBuffer
|
|
951
|
+
).abs();
|
|
952
|
+
|
|
953
|
+
netQuoteValue = netQuoteValue.sub(weightedTokenValue);
|
|
954
|
+
} else {
|
|
955
|
+
const weightedTokenValue = this.getSpotAssetValue(
|
|
956
|
+
tokenAmount,
|
|
957
|
+
strictOraclePrice,
|
|
958
|
+
spotMarketAccount,
|
|
959
|
+
marginCategory
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
netQuoteValue = netQuoteValue.add(weightedTokenValue);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
if (!includeOpenOrders && countForBase) {
|
|
969
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
970
|
+
const tokenAmount = getSignedTokenAmount(
|
|
971
|
+
getTokenAmount(
|
|
972
|
+
spotPosition.scaledBalance,
|
|
973
|
+
spotMarketAccount,
|
|
974
|
+
spotPosition.balanceType
|
|
975
|
+
),
|
|
976
|
+
SpotBalanceType.BORROW
|
|
977
|
+
);
|
|
978
|
+
const liabilityValue = this.getSpotLiabilityValue(
|
|
979
|
+
tokenAmount,
|
|
980
|
+
strictOraclePrice,
|
|
981
|
+
spotMarketAccount,
|
|
982
|
+
marginCategory,
|
|
983
|
+
liquidationBuffer
|
|
984
|
+
).abs();
|
|
985
|
+
totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
|
|
986
|
+
|
|
987
|
+
continue;
|
|
988
|
+
} else {
|
|
989
|
+
const tokenAmount = getTokenAmount(
|
|
990
|
+
spotPosition.scaledBalance,
|
|
991
|
+
spotMarketAccount,
|
|
992
|
+
spotPosition.balanceType
|
|
993
|
+
);
|
|
994
|
+
const assetValue = this.getSpotAssetValue(
|
|
995
|
+
tokenAmount,
|
|
996
|
+
strictOraclePrice,
|
|
997
|
+
spotMarketAccount,
|
|
998
|
+
marginCategory
|
|
999
|
+
);
|
|
1000
|
+
totalAssetValue = totalAssetValue.add(assetValue);
|
|
1001
|
+
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
const {
|
|
1007
|
+
tokenAmount: worstCaseTokenAmount,
|
|
1008
|
+
ordersValue: worstCaseQuoteTokenAmount,
|
|
1009
|
+
} = getWorstCaseTokenAmounts(
|
|
1010
|
+
spotPosition,
|
|
1011
|
+
spotMarketAccount,
|
|
1012
|
+
strictOraclePrice,
|
|
1013
|
+
marginCategory,
|
|
1014
|
+
this.getUserAccount().maxMarginRatio
|
|
1015
|
+
);
|
|
1016
|
+
|
|
1017
|
+
if (worstCaseTokenAmount.gt(ZERO) && countForBase) {
|
|
1018
|
+
const baseAssetValue = this.getSpotAssetValue(
|
|
1019
|
+
worstCaseTokenAmount,
|
|
1020
|
+
strictOraclePrice,
|
|
1021
|
+
spotMarketAccount,
|
|
1022
|
+
marginCategory
|
|
1023
|
+
);
|
|
1024
|
+
|
|
1025
|
+
totalAssetValue = totalAssetValue.add(baseAssetValue);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
if (worstCaseTokenAmount.lt(ZERO) && countForBase) {
|
|
1029
|
+
const baseLiabilityValue = this.getSpotLiabilityValue(
|
|
1030
|
+
worstCaseTokenAmount,
|
|
1031
|
+
strictOraclePrice,
|
|
1032
|
+
spotMarketAccount,
|
|
1033
|
+
marginCategory,
|
|
1034
|
+
liquidationBuffer
|
|
1035
|
+
).abs();
|
|
1036
|
+
|
|
1037
|
+
totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (worstCaseQuoteTokenAmount.gt(ZERO) && countForQuote) {
|
|
1041
|
+
netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (worstCaseQuoteTokenAmount.lt(ZERO) && countForQuote) {
|
|
1045
|
+
let weight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
1046
|
+
if (marginCategory === 'Initial') {
|
|
1047
|
+
weight = BN.max(weight, new BN(this.getUserAccount().maxMarginRatio));
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
const weightedTokenValue = worstCaseQuoteTokenAmount
|
|
1051
|
+
.abs()
|
|
1052
|
+
.mul(weight)
|
|
1053
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
1054
|
+
|
|
1055
|
+
netQuoteValue = netQuoteValue.sub(weightedTokenValue);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
totalLiabilityValue = totalLiabilityValue.add(
|
|
1059
|
+
new BN(spotPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
if (marketIndex === undefined || marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
1064
|
+
if (netQuoteValue.gt(ZERO)) {
|
|
1065
|
+
totalAssetValue = totalAssetValue.add(netQuoteValue);
|
|
1066
|
+
} else {
|
|
1067
|
+
totalLiabilityValue = totalLiabilityValue.add(netQuoteValue.abs());
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
return { totalAssetValue, totalLiabilityValue };
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
public getSpotMarketLiabilityValue(
|
|
1075
|
+
marketIndex?: number,
|
|
1076
|
+
marginCategory?: MarginCategory,
|
|
1077
|
+
liquidationBuffer?: BN,
|
|
1078
|
+
includeOpenOrders?: boolean,
|
|
1079
|
+
strict = false,
|
|
1080
|
+
now?: BN
|
|
1081
|
+
): BN {
|
|
1082
|
+
const { totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue(
|
|
1083
|
+
marketIndex,
|
|
1084
|
+
marginCategory,
|
|
1085
|
+
liquidationBuffer,
|
|
1086
|
+
includeOpenOrders,
|
|
1087
|
+
strict,
|
|
1088
|
+
now
|
|
1089
|
+
);
|
|
1090
|
+
return totalLiabilityValue;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
getSpotLiabilityValue(
|
|
1094
|
+
tokenAmount: BN,
|
|
1095
|
+
strictOraclePrice: StrictOraclePrice,
|
|
1096
|
+
spotMarketAccount: SpotMarketAccount,
|
|
1097
|
+
marginCategory?: MarginCategory,
|
|
1098
|
+
liquidationBuffer?: BN
|
|
1099
|
+
): BN {
|
|
1100
|
+
return getSpotLiabilityValue(
|
|
1101
|
+
tokenAmount,
|
|
1102
|
+
strictOraclePrice,
|
|
1103
|
+
spotMarketAccount,
|
|
1104
|
+
this.getUserAccount().maxMarginRatio,
|
|
1105
|
+
marginCategory,
|
|
1106
|
+
liquidationBuffer
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
public getSpotMarketAssetValue(
|
|
1111
|
+
marketIndex?: number,
|
|
1112
|
+
marginCategory?: MarginCategory,
|
|
1113
|
+
includeOpenOrders?: boolean,
|
|
1114
|
+
strict = false,
|
|
1115
|
+
now?: BN
|
|
1116
|
+
): BN {
|
|
1117
|
+
const { totalAssetValue } = this.getSpotMarketAssetAndLiabilityValue(
|
|
1118
|
+
marketIndex,
|
|
1119
|
+
marginCategory,
|
|
1120
|
+
undefined,
|
|
1121
|
+
includeOpenOrders,
|
|
1122
|
+
strict,
|
|
1123
|
+
now
|
|
1124
|
+
);
|
|
1125
|
+
return totalAssetValue;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
getSpotAssetValue(
|
|
1129
|
+
tokenAmount: BN,
|
|
1130
|
+
strictOraclePrice: StrictOraclePrice,
|
|
1131
|
+
spotMarketAccount: SpotMarketAccount,
|
|
1132
|
+
marginCategory?: MarginCategory
|
|
1133
|
+
): BN {
|
|
1134
|
+
return getSpotAssetValue(
|
|
1135
|
+
tokenAmount,
|
|
1136
|
+
strictOraclePrice,
|
|
1137
|
+
spotMarketAccount,
|
|
1138
|
+
this.getUserAccount().maxMarginRatio,
|
|
1139
|
+
marginCategory
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
public getSpotPositionValue(
|
|
1144
|
+
marketIndex: number,
|
|
1145
|
+
marginCategory?: MarginCategory,
|
|
1146
|
+
includeOpenOrders?: boolean,
|
|
1147
|
+
strict = false,
|
|
1148
|
+
now?: BN
|
|
1149
|
+
): BN {
|
|
1150
|
+
const { totalAssetValue, totalLiabilityValue } =
|
|
1151
|
+
this.getSpotMarketAssetAndLiabilityValue(
|
|
1152
|
+
marketIndex,
|
|
1153
|
+
marginCategory,
|
|
1154
|
+
undefined,
|
|
1155
|
+
includeOpenOrders,
|
|
1156
|
+
strict,
|
|
1157
|
+
now
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1160
|
+
return totalAssetValue.sub(totalLiabilityValue);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
1164
|
+
const { totalAssetValue, totalLiabilityValue } =
|
|
1165
|
+
this.getSpotMarketAssetAndLiabilityValue(
|
|
1166
|
+
undefined,
|
|
1167
|
+
withWeightMarginCategory
|
|
1168
|
+
);
|
|
1169
|
+
|
|
1170
|
+
return totalAssetValue.sub(totalLiabilityValue);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* calculates TotalCollateral: collateral + unrealized pnl
|
|
1175
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1176
|
+
*/
|
|
1177
|
+
public getTotalCollateral(
|
|
1178
|
+
marginCategory: MarginCategory = 'Initial',
|
|
1179
|
+
strict = false,
|
|
1180
|
+
includeOpenOrders = true,
|
|
1181
|
+
liquidationBuffer?: BN,
|
|
1182
|
+
perpMarketIndex?: number
|
|
1183
|
+
): BN {
|
|
1184
|
+
const liquidationBufferMap = (() => {
|
|
1185
|
+
if (liquidationBuffer && perpMarketIndex !== undefined) {
|
|
1186
|
+
return new Map([[perpMarketIndex, liquidationBuffer]]);
|
|
1187
|
+
} else if (liquidationBuffer) {
|
|
1188
|
+
return new Map([['cross', liquidationBuffer]]);
|
|
1189
|
+
}
|
|
1190
|
+
return new Map();
|
|
1191
|
+
})();
|
|
1192
|
+
const marginCalc = this.getMarginCalculation(marginCategory, {
|
|
1193
|
+
strict,
|
|
1194
|
+
includeOpenOrders,
|
|
1195
|
+
liquidationBufferMap,
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
if (perpMarketIndex !== undefined) {
|
|
1199
|
+
const { totalCollateral, totalCollateralBuffer } =
|
|
1200
|
+
marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
1201
|
+
if (liquidationBuffer?.gt(ZERO)) {
|
|
1202
|
+
return totalCollateralBuffer;
|
|
1203
|
+
}
|
|
1204
|
+
return totalCollateral;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
if (liquidationBuffer?.gt(ZERO)) {
|
|
1208
|
+
return marginCalc.totalCollateralBuffer;
|
|
1209
|
+
}
|
|
1210
|
+
return marginCalc.totalCollateral;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
public getLiquidationBuffer(): Map<number | 'cross', BN> {
|
|
1214
|
+
const liquidationBufferMap = new Map<number | 'cross', BN>();
|
|
1215
|
+
if (this.isBeingLiquidated()) {
|
|
1216
|
+
liquidationBufferMap.set(
|
|
1217
|
+
'cross',
|
|
1218
|
+
new BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio)
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
for (const position of this.getActivePerpPositions()) {
|
|
1222
|
+
if (
|
|
1223
|
+
position.positionFlag &
|
|
1224
|
+
(PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)
|
|
1225
|
+
) {
|
|
1226
|
+
liquidationBufferMap.set(
|
|
1227
|
+
position.marketIndex,
|
|
1228
|
+
new BN(
|
|
1229
|
+
this.driftClient.getStateAccount().liquidationMarginBufferRatio
|
|
1230
|
+
)
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return liquidationBufferMap;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* calculates User Health by comparing total collateral and maint. margin requirement
|
|
1239
|
+
* @returns : number (value from [0, 100])
|
|
1240
|
+
*/
|
|
1241
|
+
public getHealth(perpMarketIndex?: number): number {
|
|
1242
|
+
if (this.isCrossMarginBeingLiquidated() && !perpMarketIndex) {
|
|
1243
|
+
return 0;
|
|
1244
|
+
}
|
|
1245
|
+
if (
|
|
1246
|
+
perpMarketIndex &&
|
|
1247
|
+
this.isIsolatedPositionBeingLiquidated(perpMarketIndex)
|
|
1248
|
+
) {
|
|
1249
|
+
return 0;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
const marginCalc = this.getMarginCalculation('Maintenance');
|
|
1253
|
+
|
|
1254
|
+
let totalCollateral: BN = ZERO;
|
|
1255
|
+
let maintenanceMarginReq: BN = ZERO;
|
|
1256
|
+
|
|
1257
|
+
if (perpMarketIndex != null) {
|
|
1258
|
+
const isolatedMarginCalc =
|
|
1259
|
+
marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
1260
|
+
if (isolatedMarginCalc) {
|
|
1261
|
+
totalCollateral = isolatedMarginCalc.totalCollateral;
|
|
1262
|
+
maintenanceMarginReq = isolatedMarginCalc.marginRequirement;
|
|
1263
|
+
}
|
|
1264
|
+
} else {
|
|
1265
|
+
totalCollateral = marginCalc.totalCollateral;
|
|
1266
|
+
maintenanceMarginReq = marginCalc.marginRequirement;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
let health: number;
|
|
1270
|
+
|
|
1271
|
+
if (maintenanceMarginReq.eq(ZERO) && totalCollateral.gte(ZERO)) {
|
|
1272
|
+
health = 100;
|
|
1273
|
+
} else if (totalCollateral.lte(ZERO)) {
|
|
1274
|
+
health = 0;
|
|
1275
|
+
} else {
|
|
1276
|
+
health = Math.round(
|
|
1277
|
+
Math.min(
|
|
1278
|
+
100,
|
|
1279
|
+
Math.max(
|
|
1280
|
+
0,
|
|
1281
|
+
(1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
|
|
1282
|
+
100
|
|
1283
|
+
)
|
|
1284
|
+
)
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
return health;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
calculateWeightedPerpPositionLiability(
|
|
1292
|
+
perpPosition: PerpPosition,
|
|
1293
|
+
marginCategory?: MarginCategory,
|
|
1294
|
+
liquidationBuffer?: BN,
|
|
1295
|
+
includeOpenOrders?: boolean,
|
|
1296
|
+
strict = false
|
|
1297
|
+
): BN {
|
|
1298
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
1299
|
+
perpPosition.marketIndex
|
|
1300
|
+
);
|
|
1301
|
+
|
|
1302
|
+
let valuationPrice = this.getOracleDataForPerpMarket(
|
|
1303
|
+
market.marketIndex
|
|
1304
|
+
).price;
|
|
1305
|
+
|
|
1306
|
+
if (isVariant(market.status, 'settlement')) {
|
|
1307
|
+
valuationPrice = market.expiryPrice;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
let baseAssetAmount: BN;
|
|
1311
|
+
let liabilityValue;
|
|
1312
|
+
if (includeOpenOrders) {
|
|
1313
|
+
const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
|
|
1314
|
+
calculateWorstCasePerpLiabilityValue(
|
|
1315
|
+
perpPosition,
|
|
1316
|
+
market,
|
|
1317
|
+
valuationPrice
|
|
1318
|
+
);
|
|
1319
|
+
baseAssetAmount = worstCaseBaseAssetAmount;
|
|
1320
|
+
liabilityValue = worstCaseLiabilityValue;
|
|
1321
|
+
} else {
|
|
1322
|
+
baseAssetAmount = perpPosition.baseAssetAmount;
|
|
1323
|
+
liabilityValue = calculatePerpLiabilityValue(
|
|
1324
|
+
baseAssetAmount,
|
|
1325
|
+
valuationPrice
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
if (marginCategory) {
|
|
1330
|
+
const userCustomMargin = Math.max(
|
|
1331
|
+
perpPosition.maxMarginRatio,
|
|
1332
|
+
this.getUserAccount().maxMarginRatio
|
|
1333
|
+
);
|
|
1334
|
+
let marginRatio = new BN(
|
|
1335
|
+
calculateMarketMarginRatio(
|
|
1336
|
+
market,
|
|
1337
|
+
baseAssetAmount.abs(),
|
|
1338
|
+
marginCategory,
|
|
1339
|
+
userCustomMargin
|
|
1340
|
+
)
|
|
1341
|
+
);
|
|
1342
|
+
|
|
1343
|
+
if (liquidationBuffer !== undefined) {
|
|
1344
|
+
marginRatio = marginRatio.add(liquidationBuffer);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if (isVariant(market.status, 'settlement')) {
|
|
1348
|
+
marginRatio = ZERO;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
1352
|
+
market.quoteSpotMarketIndex
|
|
1353
|
+
);
|
|
1354
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(
|
|
1355
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1356
|
+
);
|
|
1357
|
+
|
|
1358
|
+
let quotePrice;
|
|
1359
|
+
if (strict) {
|
|
1360
|
+
quotePrice = BN.max(
|
|
1361
|
+
quoteOraclePriceData.price,
|
|
1362
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
1363
|
+
);
|
|
1364
|
+
} else {
|
|
1365
|
+
quotePrice = quoteOraclePriceData.price;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
liabilityValue = liabilityValue
|
|
1369
|
+
.mul(quotePrice)
|
|
1370
|
+
.div(PRICE_PRECISION)
|
|
1371
|
+
.mul(marginRatio)
|
|
1372
|
+
.div(MARGIN_PRECISION);
|
|
1373
|
+
|
|
1374
|
+
if (includeOpenOrders) {
|
|
1375
|
+
liabilityValue = liabilityValue.add(
|
|
1376
|
+
new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
return liabilityValue;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* calculates position value of a single perp market in margin system
|
|
1386
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1387
|
+
*/
|
|
1388
|
+
public getPerpMarketLiabilityValue(
|
|
1389
|
+
marketIndex: number,
|
|
1390
|
+
marginCategory?: MarginCategory,
|
|
1391
|
+
liquidationBuffer?: BN,
|
|
1392
|
+
includeOpenOrders?: boolean,
|
|
1393
|
+
strict = false
|
|
1394
|
+
): BN {
|
|
1395
|
+
const perpPosition = this.getPerpPosition(marketIndex);
|
|
1396
|
+
return this.calculateWeightedPerpPositionLiability(
|
|
1397
|
+
perpPosition,
|
|
1398
|
+
marginCategory,
|
|
1399
|
+
liquidationBuffer,
|
|
1400
|
+
includeOpenOrders,
|
|
1401
|
+
strict
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* calculates sum of position value across all positions in margin system
|
|
1407
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1408
|
+
*/
|
|
1409
|
+
getTotalPerpPositionLiability(
|
|
1410
|
+
marginCategory?: MarginCategory,
|
|
1411
|
+
liquidationBuffer?: BN,
|
|
1412
|
+
includeOpenOrders?: boolean,
|
|
1413
|
+
strict = false
|
|
1414
|
+
): BN {
|
|
1415
|
+
return this.getActivePerpPositions().reduce(
|
|
1416
|
+
(totalPerpValue, perpPosition) => {
|
|
1417
|
+
const baseAssetValue = this.calculateWeightedPerpPositionLiability(
|
|
1418
|
+
perpPosition,
|
|
1419
|
+
marginCategory,
|
|
1420
|
+
liquidationBuffer,
|
|
1421
|
+
includeOpenOrders,
|
|
1422
|
+
strict
|
|
1423
|
+
);
|
|
1424
|
+
return totalPerpValue.add(baseAssetValue);
|
|
1425
|
+
},
|
|
1426
|
+
ZERO
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* calculates position value based on oracle
|
|
1432
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1433
|
+
*/
|
|
1434
|
+
public getPerpPositionValue(
|
|
1435
|
+
marketIndex: number,
|
|
1436
|
+
oraclePriceData: Pick<OraclePriceData, 'price'>,
|
|
1437
|
+
includeOpenOrders = false
|
|
1438
|
+
): BN {
|
|
1439
|
+
const userPosition = this.getPerpPositionOrEmpty(marketIndex);
|
|
1440
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
1441
|
+
userPosition.marketIndex
|
|
1442
|
+
);
|
|
1443
|
+
return calculateBaseAssetValueWithOracle(
|
|
1444
|
+
market,
|
|
1445
|
+
userPosition,
|
|
1446
|
+
oraclePriceData,
|
|
1447
|
+
includeOpenOrders
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* calculates position liabiltiy value in margin system
|
|
1453
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1454
|
+
*/
|
|
1455
|
+
public getPerpLiabilityValue(
|
|
1456
|
+
marketIndex: number,
|
|
1457
|
+
oraclePriceData: OraclePriceData,
|
|
1458
|
+
includeOpenOrders = false
|
|
1459
|
+
): BN {
|
|
1460
|
+
const userPosition = this.getPerpPositionOrEmpty(marketIndex);
|
|
1461
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
1462
|
+
userPosition.marketIndex
|
|
1463
|
+
);
|
|
1464
|
+
|
|
1465
|
+
if (includeOpenOrders) {
|
|
1466
|
+
return calculateWorstCasePerpLiabilityValue(
|
|
1467
|
+
userPosition,
|
|
1468
|
+
market,
|
|
1469
|
+
oraclePriceData.price
|
|
1470
|
+
).worstCaseLiabilityValue;
|
|
1471
|
+
} else {
|
|
1472
|
+
return calculatePerpLiabilityValue(
|
|
1473
|
+
userPosition.baseAssetAmount,
|
|
1474
|
+
oraclePriceData.price
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
public getPositionSide(
|
|
1480
|
+
currentPosition: Pick<PerpPosition, 'baseAssetAmount'>
|
|
1481
|
+
): PositionDirection | undefined {
|
|
1482
|
+
if (currentPosition.baseAssetAmount.gt(ZERO)) {
|
|
1483
|
+
return PositionDirection.LONG;
|
|
1484
|
+
} else if (currentPosition.baseAssetAmount.lt(ZERO)) {
|
|
1485
|
+
return PositionDirection.SHORT;
|
|
1486
|
+
} else {
|
|
1487
|
+
return undefined;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* calculates average exit price (optionally for closing up to 100% of position)
|
|
1493
|
+
* @returns : Precision PRICE_PRECISION
|
|
1494
|
+
*/
|
|
1495
|
+
public getPositionEstimatedExitPriceAndPnl(
|
|
1496
|
+
position: PerpPosition,
|
|
1497
|
+
amountToClose?: BN,
|
|
1498
|
+
useAMMClose = false
|
|
1499
|
+
): [BN, BN] {
|
|
1500
|
+
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
1501
|
+
|
|
1502
|
+
const entryPrice = calculateEntryPrice(position);
|
|
1503
|
+
|
|
1504
|
+
const oraclePriceData = this.getMMOracleDataForPerpMarket(
|
|
1505
|
+
position.marketIndex
|
|
1506
|
+
);
|
|
1507
|
+
|
|
1508
|
+
if (amountToClose) {
|
|
1509
|
+
if (amountToClose.eq(ZERO)) {
|
|
1510
|
+
return [calculateReservePrice(market, oraclePriceData), ZERO];
|
|
1511
|
+
}
|
|
1512
|
+
position = {
|
|
1513
|
+
baseAssetAmount: amountToClose,
|
|
1514
|
+
lastCumulativeFundingRate: position.lastCumulativeFundingRate,
|
|
1515
|
+
marketIndex: position.marketIndex,
|
|
1516
|
+
quoteAssetAmount: position.quoteAssetAmount,
|
|
1517
|
+
} as PerpPosition;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
let baseAssetValue: BN;
|
|
1521
|
+
|
|
1522
|
+
if (useAMMClose) {
|
|
1523
|
+
baseAssetValue = calculateBaseAssetValue(
|
|
1524
|
+
market,
|
|
1525
|
+
position,
|
|
1526
|
+
oraclePriceData
|
|
1527
|
+
);
|
|
1528
|
+
} else {
|
|
1529
|
+
baseAssetValue = calculateBaseAssetValueWithOracle(
|
|
1530
|
+
market,
|
|
1531
|
+
position,
|
|
1532
|
+
oraclePriceData
|
|
1533
|
+
);
|
|
1534
|
+
}
|
|
1535
|
+
if (position.baseAssetAmount.eq(ZERO)) {
|
|
1536
|
+
return [ZERO, ZERO];
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
const exitPrice = baseAssetValue
|
|
1540
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
1541
|
+
.mul(PRICE_PRECISION)
|
|
1542
|
+
.div(position.baseAssetAmount.abs());
|
|
1543
|
+
|
|
1544
|
+
const pnlPerBase = exitPrice.sub(entryPrice);
|
|
1545
|
+
const pnl = pnlPerBase
|
|
1546
|
+
.mul(position.baseAssetAmount)
|
|
1547
|
+
.div(PRICE_PRECISION)
|
|
1548
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
1549
|
+
|
|
1550
|
+
return [exitPrice, pnl];
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* calculates current user leverage which is (total liability size) / (net asset value)
|
|
1555
|
+
* @returns : Precision TEN_THOUSAND
|
|
1556
|
+
*/
|
|
1557
|
+
public getLeverage(includeOpenOrders = true, perpMarketIndex?: number): BN {
|
|
1558
|
+
return this.calculateLeverageFromComponents(
|
|
1559
|
+
this.getLeverageComponents(includeOpenOrders, undefined, perpMarketIndex)
|
|
1560
|
+
);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
calculateLeverageFromComponents({
|
|
1564
|
+
perpLiabilityValue,
|
|
1565
|
+
perpPnl,
|
|
1566
|
+
spotAssetValue,
|
|
1567
|
+
spotLiabilityValue,
|
|
1568
|
+
}: {
|
|
1569
|
+
perpLiabilityValue: BN;
|
|
1570
|
+
perpPnl: BN;
|
|
1571
|
+
spotAssetValue: BN;
|
|
1572
|
+
spotLiabilityValue: BN;
|
|
1573
|
+
}): BN {
|
|
1574
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1575
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1576
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1577
|
+
|
|
1578
|
+
if (netAssetValue.eq(ZERO)) {
|
|
1579
|
+
return ZERO;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
return totalLiabilityValue.mul(TEN_THOUSAND).div(netAssetValue);
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
getLeverageComponents(
|
|
1586
|
+
includeOpenOrders = true,
|
|
1587
|
+
marginCategory: MarginCategory = undefined,
|
|
1588
|
+
perpMarketIndex?: number
|
|
1589
|
+
): {
|
|
1590
|
+
perpLiabilityValue: BN;
|
|
1591
|
+
perpPnl: BN;
|
|
1592
|
+
spotAssetValue: BN;
|
|
1593
|
+
spotLiabilityValue: BN;
|
|
1594
|
+
} {
|
|
1595
|
+
if (perpMarketIndex) {
|
|
1596
|
+
const perpPosition = this.getPerpPositionOrEmpty(perpMarketIndex);
|
|
1597
|
+
const perpLiability = this.calculateWeightedPerpPositionLiability(
|
|
1598
|
+
perpPosition,
|
|
1599
|
+
marginCategory,
|
|
1600
|
+
undefined,
|
|
1601
|
+
includeOpenOrders
|
|
1602
|
+
);
|
|
1603
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
1604
|
+
perpPosition.marketIndex
|
|
1605
|
+
);
|
|
1606
|
+
|
|
1607
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(
|
|
1608
|
+
perpPosition.marketIndex
|
|
1609
|
+
);
|
|
1610
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
1611
|
+
perpMarket.quoteSpotMarketIndex
|
|
1612
|
+
);
|
|
1613
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(
|
|
1614
|
+
perpMarket.quoteSpotMarketIndex
|
|
1615
|
+
);
|
|
1616
|
+
const strictOracle = new StrictOraclePrice(
|
|
1617
|
+
quoteOraclePriceData.price,
|
|
1618
|
+
quoteOraclePriceData.twap
|
|
1619
|
+
);
|
|
1620
|
+
|
|
1621
|
+
const positionUnrealizedPnl = calculatePositionPNL(
|
|
1622
|
+
perpMarket,
|
|
1623
|
+
perpPosition,
|
|
1624
|
+
true,
|
|
1625
|
+
oraclePriceData
|
|
1626
|
+
);
|
|
1627
|
+
|
|
1628
|
+
const tokenAmount = getTokenAmount(
|
|
1629
|
+
perpPosition.isolatedPositionScaledBalance ?? ZERO,
|
|
1630
|
+
quoteSpotMarket,
|
|
1631
|
+
SpotBalanceType.DEPOSIT
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
const spotAssetValue = getStrictTokenValue(
|
|
1635
|
+
tokenAmount,
|
|
1636
|
+
quoteSpotMarket.decimals,
|
|
1637
|
+
strictOracle
|
|
1638
|
+
);
|
|
1639
|
+
|
|
1640
|
+
return {
|
|
1641
|
+
perpLiabilityValue: perpLiability,
|
|
1642
|
+
perpPnl: positionUnrealizedPnl,
|
|
1643
|
+
spotAssetValue,
|
|
1644
|
+
spotLiabilityValue: ZERO,
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
const perpLiability = this.getTotalPerpPositionLiability(
|
|
1649
|
+
marginCategory,
|
|
1650
|
+
undefined,
|
|
1651
|
+
includeOpenOrders
|
|
1652
|
+
);
|
|
1653
|
+
const perpPnl = this.getUnrealizedPNL(true, undefined, marginCategory);
|
|
1654
|
+
|
|
1655
|
+
const {
|
|
1656
|
+
totalAssetValue: spotAssetValue,
|
|
1657
|
+
totalLiabilityValue: spotLiabilityValue,
|
|
1658
|
+
} = this.getSpotMarketAssetAndLiabilityValue(
|
|
1659
|
+
undefined,
|
|
1660
|
+
marginCategory,
|
|
1661
|
+
undefined,
|
|
1662
|
+
includeOpenOrders
|
|
1663
|
+
);
|
|
1664
|
+
|
|
1665
|
+
const isolatedDeposits =
|
|
1666
|
+
marginCategory === undefined
|
|
1667
|
+
? this.getTotalIsolatedPositionDeposits()
|
|
1668
|
+
: ZERO;
|
|
1669
|
+
|
|
1670
|
+
return {
|
|
1671
|
+
perpLiabilityValue: perpLiability,
|
|
1672
|
+
perpPnl,
|
|
1673
|
+
spotAssetValue: spotAssetValue.add(isolatedDeposits),
|
|
1674
|
+
spotLiabilityValue,
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
isDustDepositPosition(spotMarketAccount: SpotMarketAccount): boolean {
|
|
1679
|
+
const marketIndex = spotMarketAccount.marketIndex;
|
|
1680
|
+
|
|
1681
|
+
const spotPosition = this.getSpotPosition(spotMarketAccount.marketIndex);
|
|
1682
|
+
|
|
1683
|
+
if (isSpotPositionAvailable(spotPosition)) {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const depositAmount = this.getTokenAmount(spotMarketAccount.marketIndex);
|
|
1688
|
+
|
|
1689
|
+
if (depositAmount.lte(ZERO)) {
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(marketIndex);
|
|
1694
|
+
|
|
1695
|
+
const strictOraclePrice = new StrictOraclePrice(
|
|
1696
|
+
oraclePriceData.price,
|
|
1697
|
+
oraclePriceData.twap
|
|
1698
|
+
);
|
|
1699
|
+
|
|
1700
|
+
const balanceValue = this.getSpotAssetValue(
|
|
1701
|
+
depositAmount,
|
|
1702
|
+
strictOraclePrice,
|
|
1703
|
+
spotMarketAccount
|
|
1704
|
+
);
|
|
1705
|
+
|
|
1706
|
+
if (balanceValue.lt(DUST_POSITION_SIZE)) {
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
getSpotMarketAccountsWithDustPosition() {
|
|
1714
|
+
const spotMarketAccounts = this.driftClient.getSpotMarketAccounts();
|
|
1715
|
+
|
|
1716
|
+
const dustPositionAccounts: SpotMarketAccount[] = [];
|
|
1717
|
+
|
|
1718
|
+
for (const spotMarketAccount of spotMarketAccounts) {
|
|
1719
|
+
const isDust = this.isDustDepositPosition(spotMarketAccount);
|
|
1720
|
+
if (isDust) {
|
|
1721
|
+
dustPositionAccounts.push(spotMarketAccount);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
return dustPositionAccounts;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
getTotalLiabilityValue(marginCategory?: MarginCategory): BN {
|
|
1729
|
+
return this.getTotalPerpPositionLiability(
|
|
1730
|
+
marginCategory,
|
|
1731
|
+
undefined,
|
|
1732
|
+
true
|
|
1733
|
+
).add(
|
|
1734
|
+
this.getSpotMarketLiabilityValue(
|
|
1735
|
+
undefined,
|
|
1736
|
+
marginCategory,
|
|
1737
|
+
undefined,
|
|
1738
|
+
true
|
|
1739
|
+
)
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
getTotalAssetValue(marginCategory?: MarginCategory): BN {
|
|
1744
|
+
const value = this.getSpotMarketAssetValue(
|
|
1745
|
+
undefined,
|
|
1746
|
+
marginCategory,
|
|
1747
|
+
true
|
|
1748
|
+
).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
1749
|
+
if (marginCategory === undefined) {
|
|
1750
|
+
return value.add(this.getTotalIsolatedPositionDeposits());
|
|
1751
|
+
}
|
|
1752
|
+
return value;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
getNetUsdValue(): BN {
|
|
1756
|
+
const netSpotValue = this.getNetSpotMarketValue();
|
|
1757
|
+
const unrealizedPnl = this.getUnrealizedPNL(true, undefined, undefined);
|
|
1758
|
+
const isolatedDeposits = this.getTotalIsolatedPositionDeposits();
|
|
1759
|
+
return netSpotValue.add(unrealizedPnl).add(isolatedDeposits);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* Calculates the all time P&L of the user.
|
|
1764
|
+
*
|
|
1765
|
+
* Net withdraws + Net spot market value + Net unrealized P&L -
|
|
1766
|
+
*/
|
|
1767
|
+
getTotalAllTimePnl(): BN {
|
|
1768
|
+
const netUsdValue = this.getNetUsdValue();
|
|
1769
|
+
const totalDeposits = this.getUserAccount().totalDeposits;
|
|
1770
|
+
const totalWithdraws = this.getUserAccount().totalWithdraws;
|
|
1771
|
+
|
|
1772
|
+
const totalPnl = netUsdValue.add(totalWithdraws).sub(totalDeposits);
|
|
1773
|
+
|
|
1774
|
+
return totalPnl;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/**
|
|
1778
|
+
* calculates max allowable leverage exceeding hitting requirement category
|
|
1779
|
+
* for large sizes where imf factor activates, result is a lower bound
|
|
1780
|
+
* @param marginCategory {Initial, Maintenance}
|
|
1781
|
+
* @returns : Precision TEN_THOUSAND
|
|
1782
|
+
*/
|
|
1783
|
+
public getMaxLeverageForPerp(
|
|
1784
|
+
perpMarketIndex: number,
|
|
1785
|
+
_marginCategory: MarginCategory = 'Initial'
|
|
1786
|
+
): BN {
|
|
1787
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1788
|
+
this.getLeverageComponents();
|
|
1789
|
+
|
|
1790
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1791
|
+
|
|
1792
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1793
|
+
|
|
1794
|
+
if (netAssetValue.eq(ZERO)) {
|
|
1795
|
+
return ZERO;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1799
|
+
|
|
1800
|
+
// absolute max fesible size (upper bound)
|
|
1801
|
+
const maxSizeQuote = BN.max(
|
|
1802
|
+
BN.min(
|
|
1803
|
+
this.getMaxTradeSizeUSDCForPerp(perpMarketIndex, PositionDirection.LONG)
|
|
1804
|
+
.tradeSize,
|
|
1805
|
+
this.getMaxTradeSizeUSDCForPerp(
|
|
1806
|
+
perpMarketIndex,
|
|
1807
|
+
PositionDirection.SHORT
|
|
1808
|
+
).tradeSize
|
|
1809
|
+
),
|
|
1810
|
+
ZERO
|
|
1811
|
+
);
|
|
1812
|
+
|
|
1813
|
+
return totalLiabilityValue
|
|
1814
|
+
.add(maxSizeQuote)
|
|
1815
|
+
.mul(TEN_THOUSAND)
|
|
1816
|
+
.div(netAssetValue);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* calculates max allowable leverage exceeding hitting requirement category
|
|
1821
|
+
* @param spotMarketIndex
|
|
1822
|
+
* @param direction
|
|
1823
|
+
* @returns : Precision TEN_THOUSAND
|
|
1824
|
+
*/
|
|
1825
|
+
public getMaxLeverageForSpot(
|
|
1826
|
+
spotMarketIndex: number,
|
|
1827
|
+
direction: PositionDirection
|
|
1828
|
+
): BN {
|
|
1829
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1830
|
+
this.getLeverageComponents();
|
|
1831
|
+
|
|
1832
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1833
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1834
|
+
|
|
1835
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1836
|
+
|
|
1837
|
+
if (netAssetValue.eq(ZERO)) {
|
|
1838
|
+
return ZERO;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
const currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
1842
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1843
|
+
);
|
|
1844
|
+
const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
1845
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1846
|
+
);
|
|
1847
|
+
const currentQuoteValue = currentQuoteAssetValue.sub(
|
|
1848
|
+
currentQuoteLiabilityValue
|
|
1849
|
+
);
|
|
1850
|
+
|
|
1851
|
+
const currentSpotMarketAssetValue =
|
|
1852
|
+
this.getSpotMarketAssetValue(spotMarketIndex);
|
|
1853
|
+
const currentSpotMarketLiabilityValue =
|
|
1854
|
+
this.getSpotMarketLiabilityValue(spotMarketIndex);
|
|
1855
|
+
const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
|
|
1856
|
+
currentSpotMarketLiabilityValue
|
|
1857
|
+
);
|
|
1858
|
+
|
|
1859
|
+
const tradeQuoteAmount = this.getMaxTradeSizeUSDCForSpot(
|
|
1860
|
+
spotMarketIndex,
|
|
1861
|
+
direction,
|
|
1862
|
+
currentQuoteAssetValue,
|
|
1863
|
+
currentSpotMarketNetValue
|
|
1864
|
+
);
|
|
1865
|
+
|
|
1866
|
+
let assetValueToAdd = ZERO;
|
|
1867
|
+
let liabilityValueToAdd = ZERO;
|
|
1868
|
+
|
|
1869
|
+
const newQuoteNetValue = isVariant(direction, 'short')
|
|
1870
|
+
? currentQuoteValue.add(tradeQuoteAmount)
|
|
1871
|
+
: currentQuoteValue.sub(tradeQuoteAmount);
|
|
1872
|
+
const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
|
|
1873
|
+
const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
|
|
1874
|
+
|
|
1875
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1876
|
+
newQuoteAssetValue.sub(currentQuoteAssetValue)
|
|
1877
|
+
);
|
|
1878
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1879
|
+
newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
|
|
1880
|
+
);
|
|
1881
|
+
|
|
1882
|
+
const newSpotMarketNetValue = isVariant(direction, 'long')
|
|
1883
|
+
? currentSpotMarketNetValue.add(tradeQuoteAmount)
|
|
1884
|
+
: currentSpotMarketNetValue.sub(tradeQuoteAmount);
|
|
1885
|
+
const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
|
|
1886
|
+
const newSpotMarketLiabilityValue = BN.min(
|
|
1887
|
+
newSpotMarketNetValue,
|
|
1888
|
+
ZERO
|
|
1889
|
+
).abs();
|
|
1890
|
+
|
|
1891
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1892
|
+
newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
|
|
1893
|
+
);
|
|
1894
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1895
|
+
newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
|
|
1896
|
+
);
|
|
1897
|
+
|
|
1898
|
+
const finalTotalAssetValue = totalAssetValue.add(assetValueToAdd);
|
|
1899
|
+
const finalTotalSpotLiability = spotLiabilityValue.add(liabilityValueToAdd);
|
|
1900
|
+
|
|
1901
|
+
const finalTotalLiabilityValue =
|
|
1902
|
+
totalLiabilityValue.add(liabilityValueToAdd);
|
|
1903
|
+
|
|
1904
|
+
const finalNetAssetValue = finalTotalAssetValue.sub(
|
|
1905
|
+
finalTotalSpotLiability
|
|
1906
|
+
);
|
|
1907
|
+
|
|
1908
|
+
return finalTotalLiabilityValue.mul(TEN_THOUSAND).div(finalNetAssetValue);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/**
|
|
1912
|
+
* calculates margin ratio: 1 / leverage
|
|
1913
|
+
* @returns : Precision TEN_THOUSAND
|
|
1914
|
+
*/
|
|
1915
|
+
public getMarginRatio(): BN {
|
|
1916
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1917
|
+
this.getLeverageComponents();
|
|
1918
|
+
|
|
1919
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1920
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1921
|
+
|
|
1922
|
+
if (totalLiabilityValue.eq(ZERO)) {
|
|
1923
|
+
return BN_MAX;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1927
|
+
|
|
1928
|
+
return netAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
public canBeLiquidated(): AccountLiquidatableStatus & {
|
|
1932
|
+
isolatedPositions: Map<number, AccountLiquidatableStatus>;
|
|
1933
|
+
} {
|
|
1934
|
+
// Deprecated signature retained for backward compatibility in type only
|
|
1935
|
+
// but implementation now delegates to the new Map-based API and returns cross margin status.
|
|
1936
|
+
const map = this.getLiquidationStatuses();
|
|
1937
|
+
const cross = map.get('cross');
|
|
1938
|
+
const isolatedPositions: Map<number, AccountLiquidatableStatus> = new Map(
|
|
1939
|
+
Array.from(map.entries())
|
|
1940
|
+
.filter(
|
|
1941
|
+
(e): e is [number, AccountLiquidatableStatus] => e[0] !== 'cross'
|
|
1942
|
+
)
|
|
1943
|
+
.map(([key, value]) => [key, value])
|
|
1944
|
+
);
|
|
1945
|
+
return cross
|
|
1946
|
+
? { ...cross, isolatedPositions }
|
|
1947
|
+
: {
|
|
1948
|
+
canBeLiquidated: false,
|
|
1949
|
+
marginRequirement: ZERO,
|
|
1950
|
+
totalCollateral: ZERO,
|
|
1951
|
+
isolatedPositions,
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
/**
|
|
1956
|
+
* New API: Returns liquidation status for cross and each isolated perp position.
|
|
1957
|
+
* Map keys:
|
|
1958
|
+
* - 'cross' for cross margin
|
|
1959
|
+
* - marketIndex (number) for each isolated perp position
|
|
1960
|
+
*/
|
|
1961
|
+
public getLiquidationStatuses(
|
|
1962
|
+
marginCalc?: MarginCalculation
|
|
1963
|
+
): Map<'cross' | number, AccountLiquidatableStatus> {
|
|
1964
|
+
// If not provided, use buffer-aware calc for canBeLiquidated checks
|
|
1965
|
+
if (!marginCalc) {
|
|
1966
|
+
const liquidationBufferMap = this.getLiquidationBuffer();
|
|
1967
|
+
marginCalc = this.getMarginCalculation('Maintenance', {
|
|
1968
|
+
liquidationBufferMap,
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
const result = new Map<'cross' | number, AccountLiquidatableStatus>();
|
|
1973
|
+
|
|
1974
|
+
// Cross margin status
|
|
1975
|
+
const crossTotalCollateral = marginCalc.totalCollateral;
|
|
1976
|
+
const crossMarginRequirement = marginCalc.marginRequirement;
|
|
1977
|
+
result.set('cross', {
|
|
1978
|
+
canBeLiquidated: crossTotalCollateral.lt(crossMarginRequirement),
|
|
1979
|
+
marginRequirement: crossMarginRequirement,
|
|
1980
|
+
totalCollateral: crossTotalCollateral,
|
|
1981
|
+
});
|
|
1982
|
+
|
|
1983
|
+
// Isolated positions status
|
|
1984
|
+
for (const [
|
|
1985
|
+
marketIndex,
|
|
1986
|
+
isoCalc,
|
|
1987
|
+
] of marginCalc.isolatedMarginCalculations) {
|
|
1988
|
+
const isoTotalCollateral = isoCalc.totalCollateral;
|
|
1989
|
+
const isoMarginRequirement = isoCalc.marginRequirement;
|
|
1990
|
+
result.set(marketIndex, {
|
|
1991
|
+
canBeLiquidated: isoTotalCollateral.lt(isoMarginRequirement),
|
|
1992
|
+
marginRequirement: isoMarginRequirement,
|
|
1993
|
+
totalCollateral: isoTotalCollateral,
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
return result;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
public isBeingLiquidated(): boolean {
|
|
2001
|
+
return (
|
|
2002
|
+
this.isCrossMarginBeingLiquidated() ||
|
|
2003
|
+
this.hasIsolatedPositionBeingLiquidated()
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
public isCrossMarginBeingLiquidated(): boolean {
|
|
2008
|
+
return (
|
|
2009
|
+
(this.getUserAccount().status &
|
|
2010
|
+
(UserStatus.BEING_LIQUIDATED | UserStatus.BANKRUPT)) >
|
|
2011
|
+
0
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
/** Returns true if cross margin is currently below maintenance requirement (no buffer). */
|
|
2016
|
+
public canCrossMarginBeLiquidated(marginCalc?: MarginCalculation): boolean {
|
|
2017
|
+
const calc = marginCalc ?? this.getMarginCalculation('Maintenance');
|
|
2018
|
+
return calc.totalCollateral.lt(calc.marginRequirement);
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
public hasIsolatedPositionBeingLiquidated(): boolean {
|
|
2022
|
+
return this.getActivePerpPositions().some(
|
|
2023
|
+
(position) =>
|
|
2024
|
+
(position.positionFlag &
|
|
2025
|
+
(PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)) >
|
|
2026
|
+
0
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
public isIsolatedPositionBeingLiquidated(perpMarketIndex: number): boolean {
|
|
2031
|
+
const position = this.getActivePerpPositions().find(
|
|
2032
|
+
(position) => position.marketIndex === perpMarketIndex
|
|
2033
|
+
);
|
|
2034
|
+
|
|
2035
|
+
return (
|
|
2036
|
+
(position?.positionFlag &
|
|
2037
|
+
(PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)) >
|
|
2038
|
+
0
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
/** Returns true if any isolated perp position is currently below its maintenance requirement (no buffer). */
|
|
2043
|
+
public getLiquidatableIsolatedPositions(
|
|
2044
|
+
marginCalc?: MarginCalculation
|
|
2045
|
+
): number[] {
|
|
2046
|
+
const liquidatableIsolatedPositions = [];
|
|
2047
|
+
const calc = marginCalc ?? this.getMarginCalculation('Maintenance');
|
|
2048
|
+
for (const [marketIndex, isoCalc] of calc.isolatedMarginCalculations) {
|
|
2049
|
+
if (this.canIsolatedPositionMarginBeLiquidated(isoCalc)) {
|
|
2050
|
+
liquidatableIsolatedPositions.push(marketIndex);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return liquidatableIsolatedPositions;
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
public canIsolatedPositionMarginBeLiquidated(
|
|
2057
|
+
isolatedMarginCalculation: IsolatedMarginCalculation
|
|
2058
|
+
): boolean {
|
|
2059
|
+
return isolatedMarginCalculation.totalCollateral.lt(
|
|
2060
|
+
isolatedMarginCalculation.marginRequirement
|
|
2061
|
+
);
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
public hasStatus(status: UserStatus): boolean {
|
|
2065
|
+
return (this.getUserAccount().status & status) > 0;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
public isBankrupt(): boolean {
|
|
2069
|
+
return (this.getUserAccount().status & UserStatus.BANKRUPT) > 0;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Checks if any user position cumulative funding differs from respective market cumulative funding
|
|
2074
|
+
* @returns
|
|
2075
|
+
*/
|
|
2076
|
+
public needsToSettleFundingPayment(): boolean {
|
|
2077
|
+
for (const userPosition of this.getUserAccount().perpPositions) {
|
|
2078
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
2083
|
+
userPosition.marketIndex
|
|
2084
|
+
);
|
|
2085
|
+
if (
|
|
2086
|
+
market.amm.cumulativeFundingRateLong.eq(
|
|
2087
|
+
userPosition.lastCumulativeFundingRate
|
|
2088
|
+
) ||
|
|
2089
|
+
market.amm.cumulativeFundingRateShort.eq(
|
|
2090
|
+
userPosition.lastCumulativeFundingRate
|
|
2091
|
+
)
|
|
2092
|
+
) {
|
|
2093
|
+
continue;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
return true;
|
|
2097
|
+
}
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
/**
|
|
2102
|
+
* Calculate the liquidation price of a spot position
|
|
2103
|
+
* @param marketIndex
|
|
2104
|
+
* @returns Precision : PRICE_PRECISION
|
|
2105
|
+
*/
|
|
2106
|
+
public spotLiquidationPrice(
|
|
2107
|
+
marketIndex: number,
|
|
2108
|
+
positionBaseSizeChange: BN = ZERO
|
|
2109
|
+
): BN {
|
|
2110
|
+
const currentSpotPosition = this.getSpotPosition(marketIndex);
|
|
2111
|
+
|
|
2112
|
+
if (!currentSpotPosition) {
|
|
2113
|
+
return new BN(-1);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
2117
|
+
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
2118
|
+
const freeCollateral = BN.max(
|
|
2119
|
+
ZERO,
|
|
2120
|
+
totalCollateral.sub(maintenanceMarginRequirement)
|
|
2121
|
+
);
|
|
2122
|
+
|
|
2123
|
+
const market = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
2124
|
+
let signedTokenAmount = getSignedTokenAmount(
|
|
2125
|
+
getTokenAmount(
|
|
2126
|
+
currentSpotPosition.scaledBalance,
|
|
2127
|
+
market,
|
|
2128
|
+
currentSpotPosition.balanceType
|
|
2129
|
+
),
|
|
2130
|
+
currentSpotPosition.balanceType
|
|
2131
|
+
);
|
|
2132
|
+
signedTokenAmount = signedTokenAmount.add(positionBaseSizeChange);
|
|
2133
|
+
|
|
2134
|
+
if (signedTokenAmount.eq(ZERO)) {
|
|
2135
|
+
return new BN(-1);
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
let freeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(
|
|
2139
|
+
market,
|
|
2140
|
+
signedTokenAmount
|
|
2141
|
+
);
|
|
2142
|
+
|
|
2143
|
+
const oracle = market.oracle;
|
|
2144
|
+
const perpMarketWithSameOracle = this.driftClient
|
|
2145
|
+
.getPerpMarketAccounts()
|
|
2146
|
+
.find((market) => market.amm.oracle.equals(oracle));
|
|
2147
|
+
const oraclePrice =
|
|
2148
|
+
this.driftClient.getOracleDataForSpotMarket(marketIndex).price;
|
|
2149
|
+
if (perpMarketWithSameOracle) {
|
|
2150
|
+
const perpPosition = this.getPerpPositionOrEmpty(
|
|
2151
|
+
perpMarketWithSameOracle.marketIndex
|
|
2152
|
+
);
|
|
2153
|
+
if (perpPosition) {
|
|
2154
|
+
let freeCollateralDeltaForPerp =
|
|
2155
|
+
this.calculateFreeCollateralDeltaForPerp(
|
|
2156
|
+
perpMarketWithSameOracle,
|
|
2157
|
+
perpPosition,
|
|
2158
|
+
ZERO,
|
|
2159
|
+
oraclePrice
|
|
2160
|
+
);
|
|
2161
|
+
|
|
2162
|
+
if (freeCollateralDeltaForPerp) {
|
|
2163
|
+
const { numerator, denominator } = getMultipleBetweenOracleSources(
|
|
2164
|
+
market.oracleSource,
|
|
2165
|
+
perpMarketWithSameOracle.amm.oracleSource
|
|
2166
|
+
);
|
|
2167
|
+
freeCollateralDeltaForPerp = freeCollateralDeltaForPerp
|
|
2168
|
+
.mul(numerator)
|
|
2169
|
+
.div(denominator);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
freeCollateralDelta = freeCollateralDelta.add(
|
|
2173
|
+
freeCollateralDeltaForPerp || ZERO
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
if (freeCollateralDelta.eq(ZERO)) {
|
|
2179
|
+
return new BN(-1);
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
const liqPriceDelta = freeCollateral
|
|
2183
|
+
.mul(QUOTE_PRECISION)
|
|
2184
|
+
.div(freeCollateralDelta);
|
|
2185
|
+
|
|
2186
|
+
const liqPrice = oraclePrice.sub(liqPriceDelta);
|
|
2187
|
+
|
|
2188
|
+
if (liqPrice.lt(ZERO)) {
|
|
2189
|
+
return new BN(-1);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
return liqPrice;
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
/**
|
|
2196
|
+
* Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
|
|
2197
|
+
* @param marketIndex
|
|
2198
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
|
|
2199
|
+
* @param estimatedEntryPrice
|
|
2200
|
+
* @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
|
|
2201
|
+
* @param includeOpenOrders
|
|
2202
|
+
* @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
|
|
2203
|
+
* @returns Precision : PRICE_PRECISION
|
|
2204
|
+
*/
|
|
2205
|
+
public liquidationPrice(
|
|
2206
|
+
marketIndex: number,
|
|
2207
|
+
positionBaseSizeChange: BN = ZERO,
|
|
2208
|
+
estimatedEntryPrice: BN = ZERO,
|
|
2209
|
+
marginCategory: MarginCategory = 'Maintenance',
|
|
2210
|
+
includeOpenOrders = false,
|
|
2211
|
+
offsetCollateral = ZERO,
|
|
2212
|
+
marginType?: MarginType
|
|
2213
|
+
): BN {
|
|
2214
|
+
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
2215
|
+
|
|
2216
|
+
const oracle =
|
|
2217
|
+
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
2218
|
+
|
|
2219
|
+
const oraclePrice =
|
|
2220
|
+
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
2221
|
+
|
|
2222
|
+
const currentPerpPosition = this.getPerpPositionOrEmpty(marketIndex);
|
|
2223
|
+
|
|
2224
|
+
if (marginType === 'Isolated') {
|
|
2225
|
+
const marginCalculation = this.getMarginCalculation(marginCategory, {
|
|
2226
|
+
strict: false,
|
|
2227
|
+
includeOpenOrders,
|
|
2228
|
+
});
|
|
2229
|
+
const isolatedMarginCalculation =
|
|
2230
|
+
marginCalculation.isolatedMarginCalculations.get(marketIndex);
|
|
2231
|
+
if (!isolatedMarginCalculation) return new BN(-1);
|
|
2232
|
+
const { totalCollateral, marginRequirement } = isolatedMarginCalculation;
|
|
2233
|
+
|
|
2234
|
+
const freeCollateral = BN.max(
|
|
2235
|
+
ZERO,
|
|
2236
|
+
totalCollateral.sub(marginRequirement)
|
|
2237
|
+
).add(offsetCollateral);
|
|
2238
|
+
|
|
2239
|
+
const freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
|
|
2240
|
+
market,
|
|
2241
|
+
currentPerpPosition,
|
|
2242
|
+
positionBaseSizeChange,
|
|
2243
|
+
oraclePrice,
|
|
2244
|
+
marginCategory,
|
|
2245
|
+
includeOpenOrders
|
|
2246
|
+
);
|
|
2247
|
+
|
|
2248
|
+
if (!freeCollateralDelta || freeCollateralDelta.eq(ZERO)) {
|
|
2249
|
+
return new BN(-1);
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
const liqPriceDelta = freeCollateral
|
|
2253
|
+
.mul(QUOTE_PRECISION)
|
|
2254
|
+
.div(freeCollateralDelta);
|
|
2255
|
+
|
|
2256
|
+
const liqPrice = oraclePrice.sub(liqPriceDelta);
|
|
2257
|
+
|
|
2258
|
+
if (liqPrice.lt(ZERO)) {
|
|
2259
|
+
return new BN(-1);
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
return liqPrice;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
const totalCollateral = this.getTotalCollateral(
|
|
2266
|
+
marginCategory,
|
|
2267
|
+
false,
|
|
2268
|
+
includeOpenOrders
|
|
2269
|
+
);
|
|
2270
|
+
|
|
2271
|
+
const marginRequirement = this.getMarginRequirement(
|
|
2272
|
+
marginCategory,
|
|
2273
|
+
undefined,
|
|
2274
|
+
false,
|
|
2275
|
+
includeOpenOrders
|
|
2276
|
+
);
|
|
2277
|
+
|
|
2278
|
+
let freeCollateral = BN.max(
|
|
2279
|
+
ZERO,
|
|
2280
|
+
totalCollateral.sub(marginRequirement)
|
|
2281
|
+
).add(offsetCollateral);
|
|
2282
|
+
|
|
2283
|
+
positionBaseSizeChange = standardizeBaseAssetAmount(
|
|
2284
|
+
positionBaseSizeChange,
|
|
2285
|
+
market.amm.orderStepSize
|
|
2286
|
+
);
|
|
2287
|
+
|
|
2288
|
+
const freeCollateralChangeFromNewPosition =
|
|
2289
|
+
this.calculateEntriesEffectOnFreeCollateral(
|
|
2290
|
+
market,
|
|
2291
|
+
oraclePrice,
|
|
2292
|
+
currentPerpPosition,
|
|
2293
|
+
positionBaseSizeChange,
|
|
2294
|
+
estimatedEntryPrice,
|
|
2295
|
+
includeOpenOrders
|
|
2296
|
+
);
|
|
2297
|
+
|
|
2298
|
+
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
2299
|
+
|
|
2300
|
+
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
|
|
2301
|
+
market,
|
|
2302
|
+
currentPerpPosition,
|
|
2303
|
+
positionBaseSizeChange,
|
|
2304
|
+
oraclePrice,
|
|
2305
|
+
marginCategory,
|
|
2306
|
+
includeOpenOrders
|
|
2307
|
+
);
|
|
2308
|
+
|
|
2309
|
+
if (!freeCollateralDelta) {
|
|
2310
|
+
return new BN(-1);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
const spotMarketWithSameOracle = this.driftClient
|
|
2314
|
+
.getSpotMarketAccounts()
|
|
2315
|
+
.find((market) => market.oracle.equals(oracle));
|
|
2316
|
+
if (spotMarketWithSameOracle) {
|
|
2317
|
+
const spotPosition = this.getSpotPosition(
|
|
2318
|
+
spotMarketWithSameOracle.marketIndex
|
|
2319
|
+
);
|
|
2320
|
+
if (spotPosition) {
|
|
2321
|
+
const signedTokenAmount = getSignedTokenAmount(
|
|
2322
|
+
getTokenAmount(
|
|
2323
|
+
spotPosition.scaledBalance,
|
|
2324
|
+
spotMarketWithSameOracle,
|
|
2325
|
+
spotPosition.balanceType
|
|
2326
|
+
),
|
|
2327
|
+
spotPosition.balanceType
|
|
2328
|
+
);
|
|
2329
|
+
|
|
2330
|
+
let spotFreeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(
|
|
2331
|
+
spotMarketWithSameOracle,
|
|
2332
|
+
signedTokenAmount,
|
|
2333
|
+
marginCategory
|
|
2334
|
+
);
|
|
2335
|
+
|
|
2336
|
+
if (spotFreeCollateralDelta) {
|
|
2337
|
+
const { numerator, denominator } = getMultipleBetweenOracleSources(
|
|
2338
|
+
market.amm.oracleSource,
|
|
2339
|
+
spotMarketWithSameOracle.oracleSource
|
|
2340
|
+
);
|
|
2341
|
+
spotFreeCollateralDelta = spotFreeCollateralDelta
|
|
2342
|
+
.mul(numerator)
|
|
2343
|
+
.div(denominator);
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
freeCollateralDelta = freeCollateralDelta.add(
|
|
2347
|
+
spotFreeCollateralDelta || ZERO
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
if (freeCollateralDelta.eq(ZERO)) {
|
|
2353
|
+
return new BN(-1);
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
const liqPriceDelta = freeCollateral
|
|
2357
|
+
.mul(QUOTE_PRECISION)
|
|
2358
|
+
.div(freeCollateralDelta);
|
|
2359
|
+
|
|
2360
|
+
const liqPrice = oraclePrice.sub(liqPriceDelta);
|
|
2361
|
+
|
|
2362
|
+
if (liqPrice.lt(ZERO)) {
|
|
2363
|
+
return new BN(-1);
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
return liqPrice;
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
calculateEntriesEffectOnFreeCollateral(
|
|
2370
|
+
market: PerpMarketAccount,
|
|
2371
|
+
oraclePrice: BN,
|
|
2372
|
+
perpPosition: PerpPosition,
|
|
2373
|
+
positionBaseSizeChange: BN,
|
|
2374
|
+
estimatedEntryPrice: BN,
|
|
2375
|
+
includeOpenOrders: boolean,
|
|
2376
|
+
marginCategory: MarginCategory = 'Maintenance'
|
|
2377
|
+
): BN {
|
|
2378
|
+
let freeCollateralChange = ZERO;
|
|
2379
|
+
|
|
2380
|
+
// update free collateral to account for change in pnl from new position
|
|
2381
|
+
if (
|
|
2382
|
+
!estimatedEntryPrice.eq(ZERO) &&
|
|
2383
|
+
!positionBaseSizeChange.eq(ZERO) &&
|
|
2384
|
+
marginCategory === 'Maintenance'
|
|
2385
|
+
) {
|
|
2386
|
+
const costBasis = oraclePrice
|
|
2387
|
+
.mul(positionBaseSizeChange.abs())
|
|
2388
|
+
.div(BASE_PRECISION);
|
|
2389
|
+
const newPositionValue = estimatedEntryPrice
|
|
2390
|
+
.mul(positionBaseSizeChange.abs())
|
|
2391
|
+
.div(BASE_PRECISION);
|
|
2392
|
+
if (positionBaseSizeChange.gt(ZERO)) {
|
|
2393
|
+
freeCollateralChange = costBasis.sub(newPositionValue);
|
|
2394
|
+
} else {
|
|
2395
|
+
freeCollateralChange = newPositionValue.sub(costBasis);
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
// assume worst fee tier
|
|
2399
|
+
const takerFeeTier =
|
|
2400
|
+
this.driftClient.getStateAccount().perpFeeStructure.feeTiers[0];
|
|
2401
|
+
const takerFee = newPositionValue
|
|
2402
|
+
.muln(takerFeeTier.feeNumerator)
|
|
2403
|
+
.divn(takerFeeTier.feeDenominator);
|
|
2404
|
+
freeCollateralChange = freeCollateralChange.sub(takerFee);
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
const calculateMarginRequirement = (perpPosition: PerpPosition) => {
|
|
2408
|
+
let baseAssetAmount: BN;
|
|
2409
|
+
let liabilityValue: BN;
|
|
2410
|
+
if (includeOpenOrders) {
|
|
2411
|
+
const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
|
|
2412
|
+
calculateWorstCasePerpLiabilityValue(
|
|
2413
|
+
perpPosition,
|
|
2414
|
+
market,
|
|
2415
|
+
oraclePrice
|
|
2416
|
+
);
|
|
2417
|
+
baseAssetAmount = worstCaseBaseAssetAmount;
|
|
2418
|
+
liabilityValue = worstCaseLiabilityValue;
|
|
2419
|
+
} else {
|
|
2420
|
+
baseAssetAmount = perpPosition.baseAssetAmount;
|
|
2421
|
+
liabilityValue = calculatePerpLiabilityValue(
|
|
2422
|
+
baseAssetAmount,
|
|
2423
|
+
oraclePrice
|
|
2424
|
+
);
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
const userCustomMargin = Math.max(
|
|
2428
|
+
perpPosition.maxMarginRatio,
|
|
2429
|
+
this.getUserAccount().maxMarginRatio
|
|
2430
|
+
);
|
|
2431
|
+
const marginRatio = calculateMarketMarginRatio(
|
|
2432
|
+
market,
|
|
2433
|
+
baseAssetAmount.abs(),
|
|
2434
|
+
marginCategory,
|
|
2435
|
+
userCustomMargin
|
|
2436
|
+
);
|
|
2437
|
+
|
|
2438
|
+
return liabilityValue.mul(new BN(marginRatio)).div(MARGIN_PRECISION);
|
|
2439
|
+
};
|
|
2440
|
+
|
|
2441
|
+
const freeCollateralConsumptionBefore =
|
|
2442
|
+
calculateMarginRequirement(perpPosition);
|
|
2443
|
+
|
|
2444
|
+
const perpPositionAfter = Object.assign({}, perpPosition);
|
|
2445
|
+
perpPositionAfter.baseAssetAmount = perpPositionAfter.baseAssetAmount.add(
|
|
2446
|
+
positionBaseSizeChange
|
|
2447
|
+
);
|
|
2448
|
+
|
|
2449
|
+
const freeCollateralConsumptionAfter =
|
|
2450
|
+
calculateMarginRequirement(perpPositionAfter);
|
|
2451
|
+
|
|
2452
|
+
return freeCollateralChange.sub(
|
|
2453
|
+
freeCollateralConsumptionAfter.sub(freeCollateralConsumptionBefore)
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
calculateFreeCollateralDeltaForPerp(
|
|
2458
|
+
market: PerpMarketAccount,
|
|
2459
|
+
perpPosition: PerpPosition,
|
|
2460
|
+
positionBaseSizeChange: BN,
|
|
2461
|
+
oraclePrice: BN,
|
|
2462
|
+
marginCategory: MarginCategory = 'Maintenance',
|
|
2463
|
+
includeOpenOrders = false
|
|
2464
|
+
): BN | undefined {
|
|
2465
|
+
const baseAssetAmount = includeOpenOrders
|
|
2466
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition, market, oraclePrice)
|
|
2467
|
+
: perpPosition.baseAssetAmount;
|
|
2468
|
+
|
|
2469
|
+
// zero if include orders == false
|
|
2470
|
+
const orderBaseAssetAmount = baseAssetAmount.sub(
|
|
2471
|
+
perpPosition.baseAssetAmount
|
|
2472
|
+
);
|
|
2473
|
+
|
|
2474
|
+
const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
|
|
2475
|
+
|
|
2476
|
+
const userCustomMargin = Math.max(
|
|
2477
|
+
perpPosition.maxMarginRatio,
|
|
2478
|
+
this.getUserAccount().maxMarginRatio
|
|
2479
|
+
);
|
|
2480
|
+
|
|
2481
|
+
const marginRatio = calculateMarketMarginRatio(
|
|
2482
|
+
market,
|
|
2483
|
+
proposedBaseAssetAmount.abs(),
|
|
2484
|
+
marginCategory,
|
|
2485
|
+
userCustomMargin
|
|
2486
|
+
);
|
|
2487
|
+
|
|
2488
|
+
const marginRatioQuotePrecision = new BN(marginRatio)
|
|
2489
|
+
.mul(QUOTE_PRECISION)
|
|
2490
|
+
.div(MARGIN_PRECISION);
|
|
2491
|
+
|
|
2492
|
+
if (proposedBaseAssetAmount.eq(ZERO)) {
|
|
2493
|
+
return undefined;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
let freeCollateralDelta = ZERO;
|
|
2497
|
+
|
|
2498
|
+
if (proposedBaseAssetAmount.gt(ZERO)) {
|
|
2499
|
+
freeCollateralDelta = QUOTE_PRECISION.sub(marginRatioQuotePrecision)
|
|
2500
|
+
.mul(proposedBaseAssetAmount)
|
|
2501
|
+
.div(BASE_PRECISION);
|
|
2502
|
+
} else {
|
|
2503
|
+
freeCollateralDelta = QUOTE_PRECISION.neg()
|
|
2504
|
+
.sub(marginRatioQuotePrecision)
|
|
2505
|
+
.mul(proposedBaseAssetAmount.abs())
|
|
2506
|
+
.div(BASE_PRECISION);
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
if (!orderBaseAssetAmount.eq(ZERO)) {
|
|
2510
|
+
freeCollateralDelta = freeCollateralDelta.sub(
|
|
2511
|
+
marginRatioQuotePrecision
|
|
2512
|
+
.mul(orderBaseAssetAmount.abs())
|
|
2513
|
+
.div(BASE_PRECISION)
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
return freeCollateralDelta;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
calculateFreeCollateralDeltaForSpot(
|
|
2521
|
+
market: SpotMarketAccount,
|
|
2522
|
+
signedTokenAmount: BN,
|
|
2523
|
+
marginCategory: MarginCategory = 'Maintenance'
|
|
2524
|
+
): BN {
|
|
2525
|
+
const tokenPrecision = new BN(Math.pow(10, market.decimals));
|
|
2526
|
+
|
|
2527
|
+
if (signedTokenAmount.gt(ZERO)) {
|
|
2528
|
+
const assetWeight = calculateAssetWeight(
|
|
2529
|
+
signedTokenAmount,
|
|
2530
|
+
this.driftClient.getOracleDataForSpotMarket(market.marketIndex).price,
|
|
2531
|
+
market,
|
|
2532
|
+
marginCategory
|
|
2533
|
+
);
|
|
2534
|
+
|
|
2535
|
+
return QUOTE_PRECISION.mul(assetWeight)
|
|
2536
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION)
|
|
2537
|
+
.mul(signedTokenAmount)
|
|
2538
|
+
.div(tokenPrecision);
|
|
2539
|
+
} else {
|
|
2540
|
+
const liabilityWeight = calculateLiabilityWeight(
|
|
2541
|
+
signedTokenAmount.abs(),
|
|
2542
|
+
market,
|
|
2543
|
+
marginCategory
|
|
2544
|
+
);
|
|
2545
|
+
|
|
2546
|
+
return QUOTE_PRECISION.neg()
|
|
2547
|
+
.mul(liabilityWeight)
|
|
2548
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION)
|
|
2549
|
+
.mul(signedTokenAmount.abs())
|
|
2550
|
+
.div(tokenPrecision);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
/**
|
|
2555
|
+
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
|
2556
|
+
* @param positionMarketIndex
|
|
2557
|
+
* @param closeQuoteAmount
|
|
2558
|
+
* @returns : Precision PRICE_PRECISION
|
|
2559
|
+
*/
|
|
2560
|
+
public liquidationPriceAfterClose(
|
|
2561
|
+
positionMarketIndex: number,
|
|
2562
|
+
closeQuoteAmount: BN,
|
|
2563
|
+
estimatedEntryPrice: BN = ZERO
|
|
2564
|
+
): BN {
|
|
2565
|
+
const currentPosition = this.getPerpPositionOrEmpty(positionMarketIndex);
|
|
2566
|
+
|
|
2567
|
+
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
2568
|
+
.mul(closeQuoteAmount)
|
|
2569
|
+
.div(currentPosition.quoteAssetAmount.abs())
|
|
2570
|
+
.add(
|
|
2571
|
+
currentPosition.baseAssetAmount
|
|
2572
|
+
.mul(closeQuoteAmount)
|
|
2573
|
+
.mod(currentPosition.quoteAssetAmount.abs())
|
|
2574
|
+
)
|
|
2575
|
+
.neg();
|
|
2576
|
+
|
|
2577
|
+
return this.liquidationPrice(
|
|
2578
|
+
positionMarketIndex,
|
|
2579
|
+
closeBaseAmount,
|
|
2580
|
+
estimatedEntryPrice
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
public getMarginUSDCRequiredForTrade(
|
|
2585
|
+
targetMarketIndex: number,
|
|
2586
|
+
baseSize: BN,
|
|
2587
|
+
estEntryPrice?: BN,
|
|
2588
|
+
perpMarketMaxMarginRatio?: number
|
|
2589
|
+
): BN {
|
|
2590
|
+
const maxMarginRatio = Math.max(
|
|
2591
|
+
perpMarketMaxMarginRatio,
|
|
2592
|
+
this.getUserAccount().maxMarginRatio
|
|
2593
|
+
);
|
|
2594
|
+
return calculateMarginUSDCRequiredForTrade(
|
|
2595
|
+
this.driftClient,
|
|
2596
|
+
targetMarketIndex,
|
|
2597
|
+
baseSize,
|
|
2598
|
+
maxMarginRatio,
|
|
2599
|
+
estEntryPrice
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
public getCollateralDepositRequiredForTrade(
|
|
2604
|
+
targetMarketIndex: number,
|
|
2605
|
+
baseSize: BN,
|
|
2606
|
+
collateralIndex: number,
|
|
2607
|
+
perpMarketMaxMarginRatio?: number
|
|
2608
|
+
): BN {
|
|
2609
|
+
const maxMarginRatio = Math.max(
|
|
2610
|
+
perpMarketMaxMarginRatio,
|
|
2611
|
+
this.getUserAccount().maxMarginRatio
|
|
2612
|
+
);
|
|
2613
|
+
return calculateCollateralDepositRequiredForTrade(
|
|
2614
|
+
this.driftClient,
|
|
2615
|
+
targetMarketIndex,
|
|
2616
|
+
baseSize,
|
|
2617
|
+
collateralIndex,
|
|
2618
|
+
maxMarginRatio
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
/**
|
|
2623
|
+
* Separates the max trade size into two parts:
|
|
2624
|
+
* - tradeSize: The maximum trade size for target direction
|
|
2625
|
+
* - oppositeSideTradeSize: the trade size for closing the opposite direction
|
|
2626
|
+
* @param targetMarketIndex
|
|
2627
|
+
* @param tradeSide
|
|
2628
|
+
* @returns { tradeSize: BN, oppositeSideTradeSize: BN} : Precision QUOTE_PRECISION
|
|
2629
|
+
*/
|
|
2630
|
+
public getMaxTradeSizeUSDCForPerp(
|
|
2631
|
+
targetMarketIndex: number,
|
|
2632
|
+
tradeSide: PositionDirection,
|
|
2633
|
+
maxMarginRatio = undefined,
|
|
2634
|
+
positionType: 'isolated' | 'cross' = 'cross'
|
|
2635
|
+
): { tradeSize: BN; oppositeSideTradeSize: BN } {
|
|
2636
|
+
let tradeSize = ZERO;
|
|
2637
|
+
let oppositeSideTradeSize = ZERO;
|
|
2638
|
+
const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
|
|
2639
|
+
|
|
2640
|
+
const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
|
|
2641
|
+
|
|
2642
|
+
const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
|
|
2643
|
+
? 'short'
|
|
2644
|
+
: 'long';
|
|
2645
|
+
|
|
2646
|
+
const targetingSameSide = !currentPosition
|
|
2647
|
+
? true
|
|
2648
|
+
: targetSide === currentPositionSide;
|
|
2649
|
+
|
|
2650
|
+
const oracleData = this.getMMOracleDataForPerpMarket(targetMarketIndex);
|
|
2651
|
+
|
|
2652
|
+
const marketAccount =
|
|
2653
|
+
this.driftClient.getPerpMarketAccount(targetMarketIndex);
|
|
2654
|
+
|
|
2655
|
+
// add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
|
|
2656
|
+
const oppositeSizeLiabilityValue = targetingSameSide
|
|
2657
|
+
? ZERO
|
|
2658
|
+
: calculatePerpLiabilityValue(
|
|
2659
|
+
currentPosition.baseAssetAmount,
|
|
2660
|
+
oracleData.price
|
|
2661
|
+
);
|
|
2662
|
+
|
|
2663
|
+
const maxPositionSize = this.getPerpBuyingPower(
|
|
2664
|
+
targetMarketIndex,
|
|
2665
|
+
ZERO,
|
|
2666
|
+
maxMarginRatio,
|
|
2667
|
+
positionType
|
|
2668
|
+
);
|
|
2669
|
+
|
|
2670
|
+
if (maxPositionSize.gte(ZERO)) {
|
|
2671
|
+
if (oppositeSizeLiabilityValue.eq(ZERO)) {
|
|
2672
|
+
// case 1 : Regular trade where current total position less than max, and no opposite position to account for
|
|
2673
|
+
// do nothing
|
|
2674
|
+
tradeSize = maxPositionSize;
|
|
2675
|
+
} else {
|
|
2676
|
+
// case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
|
|
2677
|
+
tradeSize = maxPositionSize.add(oppositeSizeLiabilityValue);
|
|
2678
|
+
oppositeSideTradeSize = oppositeSizeLiabilityValue;
|
|
2679
|
+
}
|
|
2680
|
+
} else {
|
|
2681
|
+
// current leverage is greater than max leverage - can only reduce position size
|
|
2682
|
+
|
|
2683
|
+
if (!targetingSameSide) {
|
|
2684
|
+
const perpLiabilityValue = calculatePerpLiabilityValue(
|
|
2685
|
+
currentPosition.baseAssetAmount,
|
|
2686
|
+
oracleData.price
|
|
2687
|
+
);
|
|
2688
|
+
const totalCollateral = this.getTotalCollateral();
|
|
2689
|
+
const marginRequirement = this.getInitialMarginRequirement();
|
|
2690
|
+
const marginRatio = Math.max(
|
|
2691
|
+
currentPosition.maxMarginRatio,
|
|
2692
|
+
this.getUserAccount().maxMarginRatio
|
|
2693
|
+
);
|
|
2694
|
+
const marginFreedByClosing = perpLiabilityValue
|
|
2695
|
+
.mul(new BN(marginRatio))
|
|
2696
|
+
.div(MARGIN_PRECISION);
|
|
2697
|
+
const marginRequirementAfterClosing =
|
|
2698
|
+
marginRequirement.sub(marginFreedByClosing);
|
|
2699
|
+
|
|
2700
|
+
if (marginRequirementAfterClosing.gt(totalCollateral)) {
|
|
2701
|
+
oppositeSideTradeSize = perpLiabilityValue;
|
|
2702
|
+
} else {
|
|
2703
|
+
const freeCollateralAfterClose = totalCollateral.sub(
|
|
2704
|
+
marginRequirementAfterClosing
|
|
2705
|
+
);
|
|
2706
|
+
|
|
2707
|
+
const buyingPowerAfterClose =
|
|
2708
|
+
this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
2709
|
+
targetMarketIndex,
|
|
2710
|
+
freeCollateralAfterClose,
|
|
2711
|
+
ZERO,
|
|
2712
|
+
currentPosition.maxMarginRatio
|
|
2713
|
+
);
|
|
2714
|
+
oppositeSideTradeSize = perpLiabilityValue;
|
|
2715
|
+
tradeSize = buyingPowerAfterClose;
|
|
2716
|
+
}
|
|
2717
|
+
} else {
|
|
2718
|
+
// do nothing if targetting same side
|
|
2719
|
+
tradeSize = maxPositionSize;
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
const freeCollateral = this.getFreeCollateral('Initial');
|
|
2724
|
+
|
|
2725
|
+
let baseTradeSize =
|
|
2726
|
+
targetSide === 'long'
|
|
2727
|
+
? tradeSize.mul(BASE_PRECISION).div(oracleData.price)
|
|
2728
|
+
: tradeSize.mul(BASE_PRECISION).div(oracleData.price).neg();
|
|
2729
|
+
|
|
2730
|
+
let freeCollateralChangeFromNewPosition =
|
|
2731
|
+
this.calculateEntriesEffectOnFreeCollateral(
|
|
2732
|
+
marketAccount,
|
|
2733
|
+
oracleData.price,
|
|
2734
|
+
currentPosition,
|
|
2735
|
+
baseTradeSize,
|
|
2736
|
+
oracleData.price,
|
|
2737
|
+
false,
|
|
2738
|
+
'Initial'
|
|
2739
|
+
);
|
|
2740
|
+
|
|
2741
|
+
while (
|
|
2742
|
+
freeCollateralChangeFromNewPosition.isNeg() &&
|
|
2743
|
+
freeCollateralChangeFromNewPosition.abs().gt(freeCollateral)
|
|
2744
|
+
) {
|
|
2745
|
+
tradeSize = tradeSize.mul(new BN(99)).div(new BN(100));
|
|
2746
|
+
baseTradeSize =
|
|
2747
|
+
targetSide === 'long'
|
|
2748
|
+
? tradeSize.mul(BASE_PRECISION).div(oracleData.price)
|
|
2749
|
+
: tradeSize.mul(BASE_PRECISION).div(oracleData.price).neg();
|
|
2750
|
+
freeCollateralChangeFromNewPosition =
|
|
2751
|
+
this.calculateEntriesEffectOnFreeCollateral(
|
|
2752
|
+
marketAccount,
|
|
2753
|
+
oracleData.price,
|
|
2754
|
+
currentPosition,
|
|
2755
|
+
baseTradeSize,
|
|
2756
|
+
oracleData.price,
|
|
2757
|
+
false,
|
|
2758
|
+
'Initial'
|
|
2759
|
+
);
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
return { tradeSize, oppositeSideTradeSize };
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
/**
|
|
2766
|
+
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
|
2767
|
+
*
|
|
2768
|
+
* @param targetMarketIndex
|
|
2769
|
+
* @param direction
|
|
2770
|
+
* @param currentQuoteAssetValue
|
|
2771
|
+
* @param currentSpotMarketNetValue
|
|
2772
|
+
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
2773
|
+
*/
|
|
2774
|
+
public getMaxTradeSizeUSDCForSpot(
|
|
2775
|
+
targetMarketIndex: number,
|
|
2776
|
+
direction: PositionDirection,
|
|
2777
|
+
currentQuoteAssetValue?: BN,
|
|
2778
|
+
currentSpotMarketNetValue?: BN
|
|
2779
|
+
): BN {
|
|
2780
|
+
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
|
|
2781
|
+
const oraclePrice =
|
|
2782
|
+
this.driftClient.getOracleDataForSpotMarket(targetMarketIndex).price;
|
|
2783
|
+
|
|
2784
|
+
currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
2785
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
2786
|
+
);
|
|
2787
|
+
|
|
2788
|
+
currentSpotMarketNetValue =
|
|
2789
|
+
currentSpotMarketNetValue ?? this.getSpotPositionValue(targetMarketIndex);
|
|
2790
|
+
|
|
2791
|
+
let freeCollateral = this.getFreeCollateral();
|
|
2792
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
2793
|
+
market,
|
|
2794
|
+
oraclePrice,
|
|
2795
|
+
'Initial',
|
|
2796
|
+
ZERO,
|
|
2797
|
+
isVariant(direction, 'long')
|
|
2798
|
+
? SpotBalanceType.DEPOSIT
|
|
2799
|
+
: SpotBalanceType.BORROW,
|
|
2800
|
+
this.getUserAccount().maxMarginRatio
|
|
2801
|
+
);
|
|
2802
|
+
|
|
2803
|
+
let tradeAmount = ZERO;
|
|
2804
|
+
if (this.getUserAccount().isMarginTradingEnabled) {
|
|
2805
|
+
// if the user is buying/selling and already short/long, need to account for closing out short/long
|
|
2806
|
+
if (isVariant(direction, 'long') && currentSpotMarketNetValue.lt(ZERO)) {
|
|
2807
|
+
tradeAmount = currentSpotMarketNetValue.abs();
|
|
2808
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
2809
|
+
market,
|
|
2810
|
+
oraclePrice,
|
|
2811
|
+
'Initial',
|
|
2812
|
+
this.getTokenAmount(targetMarketIndex).abs(),
|
|
2813
|
+
SpotBalanceType.BORROW,
|
|
2814
|
+
this.getUserAccount().maxMarginRatio
|
|
2815
|
+
);
|
|
2816
|
+
freeCollateral = freeCollateral.add(
|
|
2817
|
+
tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
|
|
2818
|
+
);
|
|
2819
|
+
} else if (
|
|
2820
|
+
isVariant(direction, 'short') &&
|
|
2821
|
+
currentSpotMarketNetValue.gt(ZERO)
|
|
2822
|
+
) {
|
|
2823
|
+
tradeAmount = currentSpotMarketNetValue;
|
|
2824
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
2825
|
+
market,
|
|
2826
|
+
oraclePrice,
|
|
2827
|
+
'Initial',
|
|
2828
|
+
this.getTokenAmount(targetMarketIndex),
|
|
2829
|
+
SpotBalanceType.DEPOSIT,
|
|
2830
|
+
this.getUserAccount().maxMarginRatio
|
|
2831
|
+
);
|
|
2832
|
+
freeCollateral = freeCollateral.add(
|
|
2833
|
+
tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
|
|
2834
|
+
);
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
tradeAmount = tradeAmount.add(
|
|
2838
|
+
freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
|
|
2839
|
+
);
|
|
2840
|
+
} else if (isVariant(direction, 'long')) {
|
|
2841
|
+
tradeAmount = BN.min(
|
|
2842
|
+
currentQuoteAssetValue,
|
|
2843
|
+
freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
|
|
2844
|
+
);
|
|
2845
|
+
} else {
|
|
2846
|
+
tradeAmount = BN.max(ZERO, currentSpotMarketNetValue);
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
return tradeAmount;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/**
|
|
2853
|
+
* Calculates the max amount of token that can be swapped from inMarket to outMarket
|
|
2854
|
+
* Assumes swap happens at oracle price
|
|
2855
|
+
*
|
|
2856
|
+
* @param inMarketIndex
|
|
2857
|
+
* @param outMarketIndex
|
|
2858
|
+
* @param calculateSwap function to similate in to out swa
|
|
2859
|
+
* @param iterationLimit how long to run appromixation before erroring out
|
|
2860
|
+
*/
|
|
2861
|
+
public getMaxSwapAmount({
|
|
2862
|
+
inMarketIndex,
|
|
2863
|
+
outMarketIndex,
|
|
2864
|
+
calculateSwap,
|
|
2865
|
+
iterationLimit = 1000,
|
|
2866
|
+
}: {
|
|
2867
|
+
inMarketIndex: number;
|
|
2868
|
+
outMarketIndex: number;
|
|
2869
|
+
calculateSwap?: (inAmount: BN) => BN;
|
|
2870
|
+
iterationLimit?: number;
|
|
2871
|
+
}): { inAmount: BN; outAmount: BN; leverage: BN } {
|
|
2872
|
+
const inMarket = this.driftClient.getSpotMarketAccount(inMarketIndex);
|
|
2873
|
+
const outMarket = this.driftClient.getSpotMarketAccount(outMarketIndex);
|
|
2874
|
+
|
|
2875
|
+
const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
|
|
2876
|
+
const inOraclePrice = inOraclePriceData.price;
|
|
2877
|
+
const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
|
|
2878
|
+
const outOraclePrice = outOraclePriceData.price;
|
|
2879
|
+
|
|
2880
|
+
const inStrictOraclePrice = new StrictOraclePrice(inOraclePrice);
|
|
2881
|
+
const outStrictOraclePrice = new StrictOraclePrice(outOraclePrice);
|
|
2882
|
+
|
|
2883
|
+
const inPrecision = new BN(10 ** inMarket.decimals);
|
|
2884
|
+
const outPrecision = new BN(10 ** outMarket.decimals);
|
|
2885
|
+
|
|
2886
|
+
const inSpotPosition =
|
|
2887
|
+
this.getSpotPosition(inMarketIndex) ||
|
|
2888
|
+
this.getEmptySpotPosition(inMarketIndex);
|
|
2889
|
+
const outSpotPosition =
|
|
2890
|
+
this.getSpotPosition(outMarketIndex) ||
|
|
2891
|
+
this.getEmptySpotPosition(outMarketIndex);
|
|
2892
|
+
|
|
2893
|
+
const freeCollateral = this.getFreeCollateral();
|
|
2894
|
+
|
|
2895
|
+
const inContributionInitial =
|
|
2896
|
+
this.calculateSpotPositionFreeCollateralContribution(
|
|
2897
|
+
inSpotPosition,
|
|
2898
|
+
inStrictOraclePrice
|
|
2899
|
+
);
|
|
2900
|
+
const {
|
|
2901
|
+
totalAssetValue: inTotalAssetValueInitial,
|
|
2902
|
+
totalLiabilityValue: inTotalLiabilityValueInitial,
|
|
2903
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
2904
|
+
inSpotPosition,
|
|
2905
|
+
inStrictOraclePrice
|
|
2906
|
+
);
|
|
2907
|
+
const outContributionInitial =
|
|
2908
|
+
this.calculateSpotPositionFreeCollateralContribution(
|
|
2909
|
+
outSpotPosition,
|
|
2910
|
+
outStrictOraclePrice
|
|
2911
|
+
);
|
|
2912
|
+
const {
|
|
2913
|
+
totalAssetValue: outTotalAssetValueInitial,
|
|
2914
|
+
totalLiabilityValue: outTotalLiabilityValueInitial,
|
|
2915
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
2916
|
+
outSpotPosition,
|
|
2917
|
+
outStrictOraclePrice
|
|
2918
|
+
);
|
|
2919
|
+
const initialContribution = inContributionInitial.add(
|
|
2920
|
+
outContributionInitial
|
|
2921
|
+
);
|
|
2922
|
+
|
|
2923
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
2924
|
+
this.getLeverageComponents();
|
|
2925
|
+
|
|
2926
|
+
if (!calculateSwap) {
|
|
2927
|
+
calculateSwap = (inSwap: BN) => {
|
|
2928
|
+
return inSwap
|
|
2929
|
+
.mul(outPrecision)
|
|
2930
|
+
.mul(inOraclePrice)
|
|
2931
|
+
.div(outOraclePrice)
|
|
2932
|
+
.div(inPrecision);
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
let inSwap = ZERO;
|
|
2937
|
+
let outSwap = ZERO;
|
|
2938
|
+
const inTokenAmount = this.getTokenAmount(inMarketIndex);
|
|
2939
|
+
const outTokenAmount = this.getTokenAmount(outMarketIndex);
|
|
2940
|
+
|
|
2941
|
+
const inAssetWeight = calculateAssetWeight(
|
|
2942
|
+
inTokenAmount,
|
|
2943
|
+
inOraclePriceData.price,
|
|
2944
|
+
inMarket,
|
|
2945
|
+
'Initial'
|
|
2946
|
+
);
|
|
2947
|
+
const outAssetWeight = calculateAssetWeight(
|
|
2948
|
+
outTokenAmount,
|
|
2949
|
+
outOraclePriceData.price,
|
|
2950
|
+
outMarket,
|
|
2951
|
+
'Initial'
|
|
2952
|
+
);
|
|
2953
|
+
|
|
2954
|
+
const outSaferThanIn =
|
|
2955
|
+
// selling asset to close borrow
|
|
2956
|
+
(inTokenAmount.gt(ZERO) && outTokenAmount.lt(ZERO)) ||
|
|
2957
|
+
// buying asset with higher initial asset weight
|
|
2958
|
+
inAssetWeight.lte(outAssetWeight);
|
|
2959
|
+
|
|
2960
|
+
if (freeCollateral.lt(PRICE_PRECISION.divn(100))) {
|
|
2961
|
+
if (outSaferThanIn && inTokenAmount.gt(ZERO)) {
|
|
2962
|
+
inSwap = inTokenAmount;
|
|
2963
|
+
outSwap = calculateSwap(inSwap);
|
|
2964
|
+
}
|
|
2965
|
+
} else {
|
|
2966
|
+
let minSwap = ZERO;
|
|
2967
|
+
let maxSwap = BN.max(
|
|
2968
|
+
freeCollateral.mul(inPrecision).mul(new BN(100)).div(inOraclePrice), // 100x current free collateral
|
|
2969
|
+
inTokenAmount.abs().mul(new BN(10)) // 10x current position
|
|
2970
|
+
);
|
|
2971
|
+
inSwap = maxSwap.div(TWO);
|
|
2972
|
+
const error = freeCollateral.div(new BN(10000));
|
|
2973
|
+
|
|
2974
|
+
let i = 0;
|
|
2975
|
+
let freeCollateralAfter = freeCollateral;
|
|
2976
|
+
while (freeCollateralAfter.gt(error) || freeCollateralAfter.isNeg()) {
|
|
2977
|
+
outSwap = calculateSwap(inSwap);
|
|
2978
|
+
|
|
2979
|
+
const inPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
2980
|
+
inSpotPosition,
|
|
2981
|
+
inSwap.neg(),
|
|
2982
|
+
inMarket
|
|
2983
|
+
);
|
|
2984
|
+
const outPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
2985
|
+
outSpotPosition,
|
|
2986
|
+
outSwap,
|
|
2987
|
+
outMarket
|
|
2988
|
+
);
|
|
2989
|
+
|
|
2990
|
+
const inContributionAfter =
|
|
2991
|
+
this.calculateSpotPositionFreeCollateralContribution(
|
|
2992
|
+
inPositionAfter,
|
|
2993
|
+
inStrictOraclePrice
|
|
2994
|
+
);
|
|
2995
|
+
const outContributionAfter =
|
|
2996
|
+
this.calculateSpotPositionFreeCollateralContribution(
|
|
2997
|
+
outPositionAfter,
|
|
2998
|
+
outStrictOraclePrice
|
|
2999
|
+
);
|
|
3000
|
+
|
|
3001
|
+
const contributionAfter = inContributionAfter.add(outContributionAfter);
|
|
3002
|
+
|
|
3003
|
+
const contributionDelta = contributionAfter.sub(initialContribution);
|
|
3004
|
+
|
|
3005
|
+
freeCollateralAfter = freeCollateral.add(contributionDelta);
|
|
3006
|
+
|
|
3007
|
+
if (freeCollateralAfter.gt(error)) {
|
|
3008
|
+
minSwap = inSwap;
|
|
3009
|
+
inSwap = minSwap.add(maxSwap).div(TWO);
|
|
3010
|
+
} else if (freeCollateralAfter.isNeg()) {
|
|
3011
|
+
maxSwap = inSwap;
|
|
3012
|
+
inSwap = minSwap.add(maxSwap).div(TWO);
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
if (i++ > iterationLimit) {
|
|
3016
|
+
console.log('getMaxSwapAmount iteration limit reached');
|
|
3017
|
+
break;
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
const inPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
3023
|
+
inSpotPosition,
|
|
3024
|
+
inSwap.neg(),
|
|
3025
|
+
inMarket
|
|
3026
|
+
);
|
|
3027
|
+
const outPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
3028
|
+
outSpotPosition,
|
|
3029
|
+
outSwap,
|
|
3030
|
+
outMarket
|
|
3031
|
+
);
|
|
3032
|
+
|
|
3033
|
+
const {
|
|
3034
|
+
totalAssetValue: inTotalAssetValueAfter,
|
|
3035
|
+
totalLiabilityValue: inTotalLiabilityValueAfter,
|
|
3036
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3037
|
+
inPositionAfter,
|
|
3038
|
+
inStrictOraclePrice
|
|
3039
|
+
);
|
|
3040
|
+
|
|
3041
|
+
const {
|
|
3042
|
+
totalAssetValue: outTotalAssetValueAfter,
|
|
3043
|
+
totalLiabilityValue: outTotalLiabilityValueAfter,
|
|
3044
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3045
|
+
outPositionAfter,
|
|
3046
|
+
outStrictOraclePrice
|
|
3047
|
+
);
|
|
3048
|
+
|
|
3049
|
+
const spotAssetValueDelta = inTotalAssetValueAfter
|
|
3050
|
+
.add(outTotalAssetValueAfter)
|
|
3051
|
+
.sub(inTotalAssetValueInitial)
|
|
3052
|
+
.sub(outTotalAssetValueInitial);
|
|
3053
|
+
const spotLiabilityValueDelta = inTotalLiabilityValueAfter
|
|
3054
|
+
.add(outTotalLiabilityValueAfter)
|
|
3055
|
+
.sub(inTotalLiabilityValueInitial)
|
|
3056
|
+
.sub(outTotalLiabilityValueInitial);
|
|
3057
|
+
|
|
3058
|
+
const spotAssetValueAfter = spotAssetValue.add(spotAssetValueDelta);
|
|
3059
|
+
const spotLiabilityValueAfter = spotLiabilityValue.add(
|
|
3060
|
+
spotLiabilityValueDelta
|
|
3061
|
+
);
|
|
3062
|
+
|
|
3063
|
+
const leverage = this.calculateLeverageFromComponents({
|
|
3064
|
+
perpLiabilityValue,
|
|
3065
|
+
perpPnl,
|
|
3066
|
+
spotAssetValue: spotAssetValueAfter,
|
|
3067
|
+
spotLiabilityValue: spotLiabilityValueAfter,
|
|
3068
|
+
});
|
|
3069
|
+
|
|
3070
|
+
return { inAmount: inSwap, outAmount: outSwap, leverage };
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
public cloneAndUpdateSpotPosition(
|
|
3074
|
+
position: SpotPosition,
|
|
3075
|
+
tokenAmount: BN,
|
|
3076
|
+
market: SpotMarketAccount
|
|
3077
|
+
): SpotPosition {
|
|
3078
|
+
const clonedPosition = Object.assign({}, position);
|
|
3079
|
+
if (tokenAmount.eq(ZERO)) {
|
|
3080
|
+
return clonedPosition;
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
const preTokenAmount = getSignedTokenAmount(
|
|
3084
|
+
getTokenAmount(position.scaledBalance, market, position.balanceType),
|
|
3085
|
+
position.balanceType
|
|
3086
|
+
);
|
|
3087
|
+
|
|
3088
|
+
if (sigNum(preTokenAmount).eq(sigNum(tokenAmount))) {
|
|
3089
|
+
const scaledBalanceDelta = getBalance(
|
|
3090
|
+
tokenAmount.abs(),
|
|
3091
|
+
market,
|
|
3092
|
+
position.balanceType
|
|
3093
|
+
);
|
|
3094
|
+
clonedPosition.scaledBalance =
|
|
3095
|
+
clonedPosition.scaledBalance.add(scaledBalanceDelta);
|
|
3096
|
+
return clonedPosition;
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
const updateDirection = tokenAmount.isNeg()
|
|
3100
|
+
? SpotBalanceType.BORROW
|
|
3101
|
+
: SpotBalanceType.DEPOSIT;
|
|
3102
|
+
|
|
3103
|
+
if (tokenAmount.abs().gte(preTokenAmount.abs())) {
|
|
3104
|
+
clonedPosition.scaledBalance = getBalance(
|
|
3105
|
+
tokenAmount.abs().sub(preTokenAmount.abs()),
|
|
3106
|
+
market,
|
|
3107
|
+
updateDirection
|
|
3108
|
+
);
|
|
3109
|
+
clonedPosition.balanceType = updateDirection;
|
|
3110
|
+
} else {
|
|
3111
|
+
const scaledBalanceDelta = getBalance(
|
|
3112
|
+
tokenAmount.abs(),
|
|
3113
|
+
market,
|
|
3114
|
+
position.balanceType
|
|
3115
|
+
);
|
|
3116
|
+
|
|
3117
|
+
clonedPosition.scaledBalance =
|
|
3118
|
+
clonedPosition.scaledBalance.sub(scaledBalanceDelta);
|
|
3119
|
+
}
|
|
3120
|
+
return clonedPosition;
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
calculateSpotPositionFreeCollateralContribution(
|
|
3124
|
+
spotPosition: SpotPosition,
|
|
3125
|
+
strictOraclePrice: StrictOraclePrice
|
|
3126
|
+
): BN {
|
|
3127
|
+
const marginCategory = 'Initial';
|
|
3128
|
+
|
|
3129
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
3130
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
3131
|
+
|
|
3132
|
+
const { freeCollateralContribution } = getWorstCaseTokenAmounts(
|
|
3133
|
+
spotPosition,
|
|
3134
|
+
spotMarketAccount,
|
|
3135
|
+
strictOraclePrice,
|
|
3136
|
+
marginCategory,
|
|
3137
|
+
this.getUserAccount().maxMarginRatio
|
|
3138
|
+
);
|
|
3139
|
+
|
|
3140
|
+
return freeCollateralContribution;
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
calculateSpotPositionLeverageContribution(
|
|
3144
|
+
spotPosition: SpotPosition,
|
|
3145
|
+
strictOraclePrice: StrictOraclePrice
|
|
3146
|
+
): {
|
|
3147
|
+
totalAssetValue: BN;
|
|
3148
|
+
totalLiabilityValue: BN;
|
|
3149
|
+
} {
|
|
3150
|
+
let totalAssetValue = ZERO;
|
|
3151
|
+
let totalLiabilityValue = ZERO;
|
|
3152
|
+
|
|
3153
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
3154
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
3155
|
+
|
|
3156
|
+
const { tokenValue, ordersValue } = getWorstCaseTokenAmounts(
|
|
3157
|
+
spotPosition,
|
|
3158
|
+
spotMarketAccount,
|
|
3159
|
+
strictOraclePrice,
|
|
3160
|
+
'Initial',
|
|
3161
|
+
this.getUserAccount().maxMarginRatio
|
|
3162
|
+
);
|
|
3163
|
+
|
|
3164
|
+
if (tokenValue.gte(ZERO)) {
|
|
3165
|
+
totalAssetValue = tokenValue;
|
|
3166
|
+
} else {
|
|
3167
|
+
totalLiabilityValue = tokenValue.abs();
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
if (ordersValue.gt(ZERO)) {
|
|
3171
|
+
totalAssetValue = totalAssetValue.add(ordersValue);
|
|
3172
|
+
} else {
|
|
3173
|
+
totalLiabilityValue = totalLiabilityValue.add(ordersValue.abs());
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
return {
|
|
3177
|
+
totalAssetValue,
|
|
3178
|
+
totalLiabilityValue,
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
/**
|
|
3183
|
+
* Estimates what the user leverage will be after swap
|
|
3184
|
+
* @param inMarketIndex
|
|
3185
|
+
* @param outMarketIndex
|
|
3186
|
+
* @param inAmount
|
|
3187
|
+
* @param outAmount
|
|
3188
|
+
*/
|
|
3189
|
+
public accountLeverageAfterSwap({
|
|
3190
|
+
inMarketIndex,
|
|
3191
|
+
outMarketIndex,
|
|
3192
|
+
inAmount,
|
|
3193
|
+
outAmount,
|
|
3194
|
+
}: {
|
|
3195
|
+
inMarketIndex: number;
|
|
3196
|
+
outMarketIndex: number;
|
|
3197
|
+
inAmount: BN;
|
|
3198
|
+
outAmount: BN;
|
|
3199
|
+
}): BN {
|
|
3200
|
+
const inMarket = this.driftClient.getSpotMarketAccount(inMarketIndex);
|
|
3201
|
+
const outMarket = this.driftClient.getSpotMarketAccount(outMarketIndex);
|
|
3202
|
+
|
|
3203
|
+
const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
|
|
3204
|
+
const inOraclePrice = inOraclePriceData.price;
|
|
3205
|
+
const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
|
|
3206
|
+
const outOraclePrice = outOraclePriceData.price;
|
|
3207
|
+
const inStrictOraclePrice = new StrictOraclePrice(inOraclePrice);
|
|
3208
|
+
const outStrictOraclePrice = new StrictOraclePrice(outOraclePrice);
|
|
3209
|
+
|
|
3210
|
+
const inSpotPosition =
|
|
3211
|
+
this.getSpotPosition(inMarketIndex) ||
|
|
3212
|
+
this.getEmptySpotPosition(inMarketIndex);
|
|
3213
|
+
const outSpotPosition =
|
|
3214
|
+
this.getSpotPosition(outMarketIndex) ||
|
|
3215
|
+
this.getEmptySpotPosition(outMarketIndex);
|
|
3216
|
+
|
|
3217
|
+
const {
|
|
3218
|
+
totalAssetValue: inTotalAssetValueInitial,
|
|
3219
|
+
totalLiabilityValue: inTotalLiabilityValueInitial,
|
|
3220
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3221
|
+
inSpotPosition,
|
|
3222
|
+
inStrictOraclePrice
|
|
3223
|
+
);
|
|
3224
|
+
const {
|
|
3225
|
+
totalAssetValue: outTotalAssetValueInitial,
|
|
3226
|
+
totalLiabilityValue: outTotalLiabilityValueInitial,
|
|
3227
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3228
|
+
outSpotPosition,
|
|
3229
|
+
outStrictOraclePrice
|
|
3230
|
+
);
|
|
3231
|
+
|
|
3232
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
3233
|
+
this.getLeverageComponents();
|
|
3234
|
+
|
|
3235
|
+
const inPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
3236
|
+
inSpotPosition,
|
|
3237
|
+
inAmount.abs().neg(),
|
|
3238
|
+
inMarket
|
|
3239
|
+
);
|
|
3240
|
+
const outPositionAfter = this.cloneAndUpdateSpotPosition(
|
|
3241
|
+
outSpotPosition,
|
|
3242
|
+
outAmount.abs(),
|
|
3243
|
+
outMarket
|
|
3244
|
+
);
|
|
3245
|
+
|
|
3246
|
+
const {
|
|
3247
|
+
totalAssetValue: inTotalAssetValueAfter,
|
|
3248
|
+
totalLiabilityValue: inTotalLiabilityValueAfter,
|
|
3249
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3250
|
+
inPositionAfter,
|
|
3251
|
+
inStrictOraclePrice
|
|
3252
|
+
);
|
|
3253
|
+
|
|
3254
|
+
const {
|
|
3255
|
+
totalAssetValue: outTotalAssetValueAfter,
|
|
3256
|
+
totalLiabilityValue: outTotalLiabilityValueAfter,
|
|
3257
|
+
} = this.calculateSpotPositionLeverageContribution(
|
|
3258
|
+
outPositionAfter,
|
|
3259
|
+
outStrictOraclePrice
|
|
3260
|
+
);
|
|
3261
|
+
|
|
3262
|
+
const spotAssetValueDelta = inTotalAssetValueAfter
|
|
3263
|
+
.add(outTotalAssetValueAfter)
|
|
3264
|
+
.sub(inTotalAssetValueInitial)
|
|
3265
|
+
.sub(outTotalAssetValueInitial);
|
|
3266
|
+
const spotLiabilityValueDelta = inTotalLiabilityValueAfter
|
|
3267
|
+
.add(outTotalLiabilityValueAfter)
|
|
3268
|
+
.sub(inTotalLiabilityValueInitial)
|
|
3269
|
+
.sub(outTotalLiabilityValueInitial);
|
|
3270
|
+
|
|
3271
|
+
const spotAssetValueAfter = spotAssetValue.add(spotAssetValueDelta);
|
|
3272
|
+
const spotLiabilityValueAfter = spotLiabilityValue.add(
|
|
3273
|
+
spotLiabilityValueDelta
|
|
3274
|
+
);
|
|
3275
|
+
|
|
3276
|
+
return this.calculateLeverageFromComponents({
|
|
3277
|
+
perpLiabilityValue,
|
|
3278
|
+
perpPnl,
|
|
3279
|
+
spotAssetValue: spotAssetValueAfter,
|
|
3280
|
+
spotLiabilityValue: spotLiabilityValueAfter,
|
|
3281
|
+
});
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
// TODO - should this take the price impact of the trade into account for strict accuracy?
|
|
3285
|
+
|
|
3286
|
+
/**
|
|
3287
|
+
* Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
|
|
3288
|
+
* @param targetMarketIndex
|
|
3289
|
+
* @param: targetMarketType
|
|
3290
|
+
* @param tradeQuoteAmount
|
|
3291
|
+
* @param tradeSide
|
|
3292
|
+
* @param includeOpenOrders
|
|
3293
|
+
* @returns leverageRatio : Precision TEN_THOUSAND
|
|
3294
|
+
*/
|
|
3295
|
+
public accountLeverageRatioAfterTrade(
|
|
3296
|
+
targetMarketIndex: number,
|
|
3297
|
+
targetMarketType: MarketType,
|
|
3298
|
+
tradeQuoteAmount: BN,
|
|
3299
|
+
tradeSide: PositionDirection,
|
|
3300
|
+
includeOpenOrders = true
|
|
3301
|
+
): BN {
|
|
3302
|
+
const tradeIsPerp = isVariant(targetMarketType, 'perp');
|
|
3303
|
+
|
|
3304
|
+
if (!tradeIsPerp) {
|
|
3305
|
+
// calculate new asset/liability values for base and quote market to find new account leverage
|
|
3306
|
+
const totalLiabilityValue = this.getTotalLiabilityValue();
|
|
3307
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
3308
|
+
const spotLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
3309
|
+
undefined,
|
|
3310
|
+
undefined,
|
|
3311
|
+
undefined,
|
|
3312
|
+
includeOpenOrders
|
|
3313
|
+
);
|
|
3314
|
+
|
|
3315
|
+
const currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
3316
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
3317
|
+
undefined,
|
|
3318
|
+
includeOpenOrders
|
|
3319
|
+
);
|
|
3320
|
+
const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
3321
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
3322
|
+
undefined,
|
|
3323
|
+
undefined,
|
|
3324
|
+
includeOpenOrders
|
|
3325
|
+
);
|
|
3326
|
+
const currentQuoteValue = currentQuoteAssetValue.sub(
|
|
3327
|
+
currentQuoteLiabilityValue
|
|
3328
|
+
);
|
|
3329
|
+
|
|
3330
|
+
const currentSpotMarketAssetValue = this.getSpotMarketAssetValue(
|
|
3331
|
+
targetMarketIndex,
|
|
3332
|
+
undefined,
|
|
3333
|
+
includeOpenOrders
|
|
3334
|
+
);
|
|
3335
|
+
const currentSpotMarketLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
3336
|
+
targetMarketIndex,
|
|
3337
|
+
undefined,
|
|
3338
|
+
undefined,
|
|
3339
|
+
includeOpenOrders
|
|
3340
|
+
);
|
|
3341
|
+
const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
|
|
3342
|
+
currentSpotMarketLiabilityValue
|
|
3343
|
+
);
|
|
3344
|
+
|
|
3345
|
+
let assetValueToAdd = ZERO;
|
|
3346
|
+
let liabilityValueToAdd = ZERO;
|
|
3347
|
+
|
|
3348
|
+
const newQuoteNetValue =
|
|
3349
|
+
tradeSide == PositionDirection.SHORT
|
|
3350
|
+
? currentQuoteValue.add(tradeQuoteAmount)
|
|
3351
|
+
: currentQuoteValue.sub(tradeQuoteAmount);
|
|
3352
|
+
const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
|
|
3353
|
+
const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
|
|
3354
|
+
|
|
3355
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
3356
|
+
newQuoteAssetValue.sub(currentQuoteAssetValue)
|
|
3357
|
+
);
|
|
3358
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
3359
|
+
newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
|
|
3360
|
+
);
|
|
3361
|
+
|
|
3362
|
+
const newSpotMarketNetValue =
|
|
3363
|
+
tradeSide == PositionDirection.LONG
|
|
3364
|
+
? currentSpotMarketNetValue.add(tradeQuoteAmount)
|
|
3365
|
+
: currentSpotMarketNetValue.sub(tradeQuoteAmount);
|
|
3366
|
+
const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
|
|
3367
|
+
const newSpotMarketLiabilityValue = BN.min(
|
|
3368
|
+
newSpotMarketNetValue,
|
|
3369
|
+
ZERO
|
|
3370
|
+
).abs();
|
|
3371
|
+
|
|
3372
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
3373
|
+
newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
|
|
3374
|
+
);
|
|
3375
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
3376
|
+
newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
|
|
3377
|
+
);
|
|
3378
|
+
|
|
3379
|
+
const totalAssetValueAfterTrade = totalAssetValue.add(assetValueToAdd);
|
|
3380
|
+
const totalSpotLiabilityValueAfterTrade =
|
|
3381
|
+
spotLiabilityValue.add(liabilityValueToAdd);
|
|
3382
|
+
|
|
3383
|
+
const totalLiabilityValueAfterTrade =
|
|
3384
|
+
totalLiabilityValue.add(liabilityValueToAdd);
|
|
3385
|
+
|
|
3386
|
+
const netAssetValueAfterTrade = totalAssetValueAfterTrade.sub(
|
|
3387
|
+
totalSpotLiabilityValueAfterTrade
|
|
3388
|
+
);
|
|
3389
|
+
|
|
3390
|
+
if (netAssetValueAfterTrade.eq(ZERO)) {
|
|
3391
|
+
return ZERO;
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
const newLeverage = totalLiabilityValueAfterTrade
|
|
3395
|
+
.mul(TEN_THOUSAND)
|
|
3396
|
+
.div(netAssetValueAfterTrade);
|
|
3397
|
+
|
|
3398
|
+
return newLeverage;
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
|
|
3402
|
+
|
|
3403
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(targetMarketIndex);
|
|
3404
|
+
const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
|
|
3405
|
+
|
|
3406
|
+
let {
|
|
3407
|
+
// eslint-disable-next-line prefer-const
|
|
3408
|
+
worstCaseBaseAssetAmount: worstCaseBase,
|
|
3409
|
+
worstCaseLiabilityValue: currentPositionQuoteAmount,
|
|
3410
|
+
} = calculateWorstCasePerpLiabilityValue(
|
|
3411
|
+
currentPosition,
|
|
3412
|
+
perpMarket,
|
|
3413
|
+
oracleData.price
|
|
3414
|
+
);
|
|
3415
|
+
|
|
3416
|
+
// current side is short if position base asset amount is negative OR there is no position open but open orders are short
|
|
3417
|
+
const currentSide =
|
|
3418
|
+
currentPosition.baseAssetAmount.isNeg() ||
|
|
3419
|
+
(currentPosition.baseAssetAmount.eq(ZERO) && worstCaseBase.isNeg())
|
|
3420
|
+
? PositionDirection.SHORT
|
|
3421
|
+
: PositionDirection.LONG;
|
|
3422
|
+
|
|
3423
|
+
if (currentSide === PositionDirection.SHORT)
|
|
3424
|
+
currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
|
|
3425
|
+
|
|
3426
|
+
if (tradeSide === PositionDirection.SHORT)
|
|
3427
|
+
tradeQuoteAmount = tradeQuoteAmount.neg();
|
|
3428
|
+
|
|
3429
|
+
const currentPerpPositionAfterTrade = currentPositionQuoteAmount
|
|
3430
|
+
.add(tradeQuoteAmount)
|
|
3431
|
+
.abs();
|
|
3432
|
+
|
|
3433
|
+
const totalPositionAfterTradeExcludingTargetMarket =
|
|
3434
|
+
this.getTotalPerpPositionValueExcludingMarket(
|
|
3435
|
+
targetMarketIndex,
|
|
3436
|
+
undefined,
|
|
3437
|
+
undefined,
|
|
3438
|
+
includeOpenOrders
|
|
3439
|
+
);
|
|
3440
|
+
|
|
3441
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
3442
|
+
|
|
3443
|
+
const totalPerpPositionLiability = currentPerpPositionAfterTrade
|
|
3444
|
+
.add(totalPositionAfterTradeExcludingTargetMarket)
|
|
3445
|
+
.abs();
|
|
3446
|
+
|
|
3447
|
+
const totalSpotLiability = this.getSpotMarketLiabilityValue(
|
|
3448
|
+
undefined,
|
|
3449
|
+
undefined,
|
|
3450
|
+
undefined,
|
|
3451
|
+
includeOpenOrders
|
|
3452
|
+
);
|
|
3453
|
+
|
|
3454
|
+
const totalLiabilitiesAfterTrade =
|
|
3455
|
+
totalPerpPositionLiability.add(totalSpotLiability);
|
|
3456
|
+
|
|
3457
|
+
const netAssetValue = totalAssetValue.sub(totalSpotLiability);
|
|
3458
|
+
|
|
3459
|
+
if (netAssetValue.eq(ZERO)) {
|
|
3460
|
+
return ZERO;
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
const newLeverage = totalLiabilitiesAfterTrade
|
|
3464
|
+
.mul(TEN_THOUSAND)
|
|
3465
|
+
.div(netAssetValue);
|
|
3466
|
+
|
|
3467
|
+
return newLeverage;
|
|
3468
|
+
}
|
|
3469
|
+
|
|
3470
|
+
public getUserFeeTier(marketType: MarketType, now?: BN) {
|
|
3471
|
+
const state = this.driftClient.getStateAccount();
|
|
3472
|
+
|
|
3473
|
+
const feeTierIndex = 0;
|
|
3474
|
+
if (isVariant(marketType, 'perp')) {
|
|
3475
|
+
const userStatsAccount: UserStatsAccount = this.driftClient
|
|
3476
|
+
.getUserStats()
|
|
3477
|
+
.getAccount();
|
|
3478
|
+
|
|
3479
|
+
const total30dVolume = getUser30dRollingVolumeEstimate(
|
|
3480
|
+
userStatsAccount,
|
|
3481
|
+
now
|
|
3482
|
+
);
|
|
3483
|
+
const stakedGovAssetAmount = userStatsAccount.ifStakedGovTokenAmount;
|
|
3484
|
+
|
|
3485
|
+
const volumeThresholds = [
|
|
3486
|
+
new BN(2_000_000).mul(QUOTE_PRECISION),
|
|
3487
|
+
new BN(10_000_000).mul(QUOTE_PRECISION),
|
|
3488
|
+
new BN(20_000_000).mul(QUOTE_PRECISION),
|
|
3489
|
+
new BN(80_000_000).mul(QUOTE_PRECISION),
|
|
3490
|
+
new BN(200_000_000).mul(QUOTE_PRECISION),
|
|
3491
|
+
];
|
|
3492
|
+
const stakeThresholds = [
|
|
3493
|
+
new BN(1_000 - 1).mul(QUOTE_PRECISION),
|
|
3494
|
+
new BN(10_000 - 1).mul(QUOTE_PRECISION),
|
|
3495
|
+
new BN(50_000 - 1).mul(QUOTE_PRECISION),
|
|
3496
|
+
new BN(100_000 - 1).mul(QUOTE_PRECISION),
|
|
3497
|
+
new BN(250_000 - 5).mul(QUOTE_PRECISION),
|
|
3498
|
+
];
|
|
3499
|
+
const stakeBenefitFrac = [0, 5, 10, 20, 30, 40];
|
|
3500
|
+
|
|
3501
|
+
let feeTierIndex = 5;
|
|
3502
|
+
for (let i = 0; i < volumeThresholds.length; i++) {
|
|
3503
|
+
if (total30dVolume.lt(volumeThresholds[i])) {
|
|
3504
|
+
feeTierIndex = i;
|
|
3505
|
+
break;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
let stakeBenefitIndex = 5;
|
|
3510
|
+
for (let i = 0; i < stakeThresholds.length; i++) {
|
|
3511
|
+
if (stakedGovAssetAmount.lt(stakeThresholds[i])) {
|
|
3512
|
+
stakeBenefitIndex = i;
|
|
3513
|
+
break;
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
const stakeBenefit = stakeBenefitFrac[stakeBenefitIndex];
|
|
3518
|
+
|
|
3519
|
+
const tier = { ...state.perpFeeStructure.feeTiers[feeTierIndex] };
|
|
3520
|
+
|
|
3521
|
+
if (stakeBenefit > 0) {
|
|
3522
|
+
tier.feeNumerator = (tier.feeNumerator * (100 - stakeBenefit)) / 100;
|
|
3523
|
+
|
|
3524
|
+
tier.makerRebateNumerator =
|
|
3525
|
+
(tier.makerRebateNumerator * (100 + stakeBenefit)) / 100;
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
return tier;
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
return state.spotFeeStructure.feeTiers[feeTierIndex];
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
/**
|
|
3535
|
+
* Calculates how much perp fee will be taken for a given sized trade
|
|
3536
|
+
* @param quoteAmount
|
|
3537
|
+
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
3538
|
+
*/
|
|
3539
|
+
public calculateFeeForQuoteAmount(quoteAmount: BN, marketIndex?: number): BN {
|
|
3540
|
+
if (marketIndex !== undefined) {
|
|
3541
|
+
const takerFeeMultiplier = this.driftClient.getMarketFees(
|
|
3542
|
+
MarketType.PERP,
|
|
3543
|
+
marketIndex,
|
|
3544
|
+
this
|
|
3545
|
+
).takerFee;
|
|
3546
|
+
const feeAmountNum =
|
|
3547
|
+
BigNum.from(quoteAmount, QUOTE_PRECISION_EXP).toNum() *
|
|
3548
|
+
takerFeeMultiplier;
|
|
3549
|
+
return BigNum.fromPrint(feeAmountNum.toString(), QUOTE_PRECISION_EXP).val;
|
|
3550
|
+
} else {
|
|
3551
|
+
const feeTier = this.getUserFeeTier(MarketType.PERP);
|
|
3552
|
+
return quoteAmount
|
|
3553
|
+
.mul(new BN(feeTier.feeNumerator))
|
|
3554
|
+
.div(new BN(feeTier.feeDenominator));
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
/**
|
|
3559
|
+
* Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
|
|
3560
|
+
* it will return the max withdrawal amount without opening a liability for the user
|
|
3561
|
+
* @param marketIndex
|
|
3562
|
+
* @returns withdrawalLimit : Precision is the token precision for the chosen SpotMarket
|
|
3563
|
+
*/
|
|
3564
|
+
public getWithdrawalLimit(marketIndex: number, reduceOnly?: boolean): BN {
|
|
3565
|
+
const nowTs = new BN(Math.floor(Date.now() / 1000));
|
|
3566
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
3567
|
+
|
|
3568
|
+
// eslint-disable-next-line prefer-const
|
|
3569
|
+
let { borrowLimit, withdrawLimit } = calculateWithdrawLimit(
|
|
3570
|
+
spotMarket,
|
|
3571
|
+
nowTs
|
|
3572
|
+
);
|
|
3573
|
+
|
|
3574
|
+
const freeCollateral = this.getFreeCollateral();
|
|
3575
|
+
const initialMarginRequirement = this.getInitialMarginRequirement();
|
|
3576
|
+
const oracleData = this.getOracleDataForSpotMarket(marketIndex);
|
|
3577
|
+
const { numeratorScale, denominatorScale } =
|
|
3578
|
+
spotMarket.decimals > 6
|
|
3579
|
+
? {
|
|
3580
|
+
numeratorScale: new BN(10).pow(new BN(spotMarket.decimals - 6)),
|
|
3581
|
+
denominatorScale: new BN(1),
|
|
3582
|
+
}
|
|
3583
|
+
: {
|
|
3584
|
+
numeratorScale: new BN(1),
|
|
3585
|
+
denominatorScale: new BN(10).pow(new BN(6 - spotMarket.decimals)),
|
|
3586
|
+
};
|
|
3587
|
+
|
|
3588
|
+
const { canBypass, depositAmount: userDepositAmount } =
|
|
3589
|
+
this.canBypassWithdrawLimits(marketIndex);
|
|
3590
|
+
if (canBypass) {
|
|
3591
|
+
withdrawLimit = BN.max(withdrawLimit, userDepositAmount);
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
const assetWeight = calculateAssetWeight(
|
|
3595
|
+
userDepositAmount,
|
|
3596
|
+
oracleData.price,
|
|
3597
|
+
spotMarket,
|
|
3598
|
+
'Initial'
|
|
3599
|
+
);
|
|
3600
|
+
|
|
3601
|
+
let amountWithdrawable;
|
|
3602
|
+
if (assetWeight.eq(ZERO)) {
|
|
3603
|
+
amountWithdrawable = userDepositAmount;
|
|
3604
|
+
} else if (initialMarginRequirement.eq(ZERO)) {
|
|
3605
|
+
amountWithdrawable = userDepositAmount;
|
|
3606
|
+
} else {
|
|
3607
|
+
amountWithdrawable = divCeil(
|
|
3608
|
+
divCeil(freeCollateral.mul(MARGIN_PRECISION), assetWeight).mul(
|
|
3609
|
+
PRICE_PRECISION
|
|
3610
|
+
),
|
|
3611
|
+
oracleData.price
|
|
3612
|
+
)
|
|
3613
|
+
.mul(numeratorScale)
|
|
3614
|
+
.div(denominatorScale);
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3617
|
+
const maxWithdrawValue = BN.min(
|
|
3618
|
+
BN.min(amountWithdrawable, userDepositAmount),
|
|
3619
|
+
withdrawLimit.abs()
|
|
3620
|
+
);
|
|
3621
|
+
|
|
3622
|
+
if (reduceOnly) {
|
|
3623
|
+
return BN.max(maxWithdrawValue, ZERO);
|
|
3624
|
+
} else {
|
|
3625
|
+
const weightedAssetValue = this.getSpotMarketAssetValue(
|
|
3626
|
+
marketIndex,
|
|
3627
|
+
'Initial',
|
|
3628
|
+
false
|
|
3629
|
+
);
|
|
3630
|
+
|
|
3631
|
+
const freeCollatAfterWithdraw = userDepositAmount.gt(ZERO)
|
|
3632
|
+
? freeCollateral.sub(weightedAssetValue)
|
|
3633
|
+
: freeCollateral;
|
|
3634
|
+
|
|
3635
|
+
const maxLiabilityAllowed = freeCollatAfterWithdraw
|
|
3636
|
+
.mul(MARGIN_PRECISION)
|
|
3637
|
+
.div(new BN(spotMarket.initialLiabilityWeight))
|
|
3638
|
+
.mul(PRICE_PRECISION)
|
|
3639
|
+
.div(oracleData.price)
|
|
3640
|
+
.mul(numeratorScale)
|
|
3641
|
+
.div(denominatorScale);
|
|
3642
|
+
|
|
3643
|
+
const maxBorrowValue = BN.min(
|
|
3644
|
+
maxWithdrawValue.add(maxLiabilityAllowed),
|
|
3645
|
+
borrowLimit.abs()
|
|
3646
|
+
);
|
|
3647
|
+
|
|
3648
|
+
return BN.max(maxBorrowValue, ZERO);
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
public canBypassWithdrawLimits(marketIndex: number): {
|
|
3653
|
+
canBypass: boolean;
|
|
3654
|
+
netDeposits: BN;
|
|
3655
|
+
depositAmount: BN;
|
|
3656
|
+
maxDepositAmount: BN;
|
|
3657
|
+
} {
|
|
3658
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
3659
|
+
const maxDepositAmount = spotMarket.withdrawGuardThreshold.div(new BN(10));
|
|
3660
|
+
const position = this.getSpotPosition(marketIndex);
|
|
3661
|
+
|
|
3662
|
+
const netDeposits = this.getUserAccount().totalDeposits.sub(
|
|
3663
|
+
this.getUserAccount().totalWithdraws
|
|
3664
|
+
);
|
|
3665
|
+
|
|
3666
|
+
if (!position) {
|
|
3667
|
+
return {
|
|
3668
|
+
canBypass: false,
|
|
3669
|
+
maxDepositAmount,
|
|
3670
|
+
depositAmount: ZERO,
|
|
3671
|
+
netDeposits,
|
|
3672
|
+
};
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
if (isVariant(position.balanceType, 'borrow')) {
|
|
3676
|
+
return {
|
|
3677
|
+
canBypass: false,
|
|
3678
|
+
maxDepositAmount,
|
|
3679
|
+
netDeposits,
|
|
3680
|
+
depositAmount: ZERO,
|
|
3681
|
+
};
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
const depositAmount = getTokenAmount(
|
|
3685
|
+
position.scaledBalance,
|
|
3686
|
+
spotMarket,
|
|
3687
|
+
SpotBalanceType.DEPOSIT
|
|
3688
|
+
);
|
|
3689
|
+
|
|
3690
|
+
if (netDeposits.lt(ZERO)) {
|
|
3691
|
+
return {
|
|
3692
|
+
canBypass: false,
|
|
3693
|
+
maxDepositAmount,
|
|
3694
|
+
depositAmount,
|
|
3695
|
+
netDeposits,
|
|
3696
|
+
};
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3699
|
+
return {
|
|
3700
|
+
canBypass: depositAmount.lt(maxDepositAmount),
|
|
3701
|
+
maxDepositAmount,
|
|
3702
|
+
netDeposits,
|
|
3703
|
+
depositAmount,
|
|
3704
|
+
};
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
public canMakeIdle(slot: BN): boolean {
|
|
3708
|
+
const userAccount = this.getUserAccount();
|
|
3709
|
+
if (userAccount.idle) {
|
|
3710
|
+
return false;
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
const { totalAssetValue, totalLiabilityValue } =
|
|
3714
|
+
this.getSpotMarketAssetAndLiabilityValue();
|
|
3715
|
+
const equity = totalAssetValue.sub(totalLiabilityValue);
|
|
3716
|
+
|
|
3717
|
+
let slotsBeforeIdle: BN;
|
|
3718
|
+
if (equity.lt(QUOTE_PRECISION.muln(1000))) {
|
|
3719
|
+
slotsBeforeIdle = new BN(9000); // 1 hour
|
|
3720
|
+
} else {
|
|
3721
|
+
slotsBeforeIdle = new BN(1512000); // 1 week
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
const userLastActiveSlot = userAccount.lastActiveSlot;
|
|
3725
|
+
const slotsSinceLastActive = slot.sub(userLastActiveSlot);
|
|
3726
|
+
if (slotsSinceLastActive.lt(slotsBeforeIdle)) {
|
|
3727
|
+
return false;
|
|
3728
|
+
}
|
|
3729
|
+
|
|
3730
|
+
if (this.isBeingLiquidated()) {
|
|
3731
|
+
return false;
|
|
3732
|
+
}
|
|
3733
|
+
|
|
3734
|
+
for (const perpPosition of userAccount.perpPositions) {
|
|
3735
|
+
if (!positionIsAvailable(perpPosition)) {
|
|
3736
|
+
return false;
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
3741
|
+
if (
|
|
3742
|
+
isVariant(spotPosition.balanceType, 'borrow') &&
|
|
3743
|
+
spotPosition.scaledBalance.gt(ZERO)
|
|
3744
|
+
) {
|
|
3745
|
+
return false;
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
if (spotPosition.openOrders !== 0) {
|
|
3749
|
+
return false;
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
for (const order of userAccount.orders) {
|
|
3754
|
+
if (isVariant(order.status, 'open')) {
|
|
3755
|
+
return false;
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
return true;
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
public canBeDeleted(
|
|
3763
|
+
userStatsAccount?: UserStatsAccount,
|
|
3764
|
+
now?: BN
|
|
3765
|
+
): { canDelete: boolean; reason?: string } {
|
|
3766
|
+
const userAccount = this.getUserAccount();
|
|
3767
|
+
const userStatsAccountToUse =
|
|
3768
|
+
userStatsAccount || this.driftClient.getUserStats().getAccount();
|
|
3769
|
+
const nowInSeconds = now || new BN(Math.floor(Date.now() / 1000));
|
|
3770
|
+
const stateAccount = this.driftClient.getStateAccount();
|
|
3771
|
+
|
|
3772
|
+
// Referrer cannot delete sub_account_id 0
|
|
3773
|
+
const isReferrer =
|
|
3774
|
+
(userStatsAccountToUse.referrerStatus & ReferrerStatus.IsReferrer) > 0;
|
|
3775
|
+
if (isReferrer && userAccount.subAccountId === 0) {
|
|
3776
|
+
return { canDelete: false, reason: 'is-subaccount-0-referrer' };
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
if (this.isBankrupt()) {
|
|
3780
|
+
return { canDelete: false, reason: 'is-bankrupt' };
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
if (this.isBeingLiquidated()) {
|
|
3784
|
+
return { canDelete: false, reason: 'is-being-liquidated' };
|
|
3785
|
+
}
|
|
3786
|
+
|
|
3787
|
+
// Any perp positions available
|
|
3788
|
+
for (const perpPosition of userAccount.perpPositions) {
|
|
3789
|
+
if (!positionIsAvailable(perpPosition)) {
|
|
3790
|
+
return { canDelete: false, reason: 'has-perp-position' };
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
// Any spot positions available
|
|
3795
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
3796
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
3797
|
+
return { canDelete: false, reason: 'has-spot-position' };
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
// No open orders
|
|
3802
|
+
for (const order of userAccount.orders) {
|
|
3803
|
+
if (isVariant(order.status, 'open')) {
|
|
3804
|
+
return { canDelete: false, reason: 'has-open-order' };
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
// Fresh account (< 13 days) with init fee must be idle
|
|
3809
|
+
if (stateAccount.maxInitializeUserFee > 0) {
|
|
3810
|
+
const minActionTs = BN.min(
|
|
3811
|
+
userStatsAccountToUse.lastFillerVolume30DTs,
|
|
3812
|
+
BN.min(
|
|
3813
|
+
userStatsAccountToUse.lastMakerVolume30DTs,
|
|
3814
|
+
userStatsAccountToUse.lastTakerVolume30DTs
|
|
3815
|
+
)
|
|
3816
|
+
);
|
|
3817
|
+
const estimatedAge = BN.max(nowInSeconds.sub(minActionTs), ZERO);
|
|
3818
|
+
if (estimatedAge.lt(new BN(ACCOUNT_AGE_DELETION_CUTOFF_SECONDS))) {
|
|
3819
|
+
if (!userAccount.idle) {
|
|
3820
|
+
return {
|
|
3821
|
+
canDelete: false,
|
|
3822
|
+
reason: 'is-not-idle-fresh-account',
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
return { canDelete: true };
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
public getSafestTiers(): { perpTier: number; spotTier: number } {
|
|
3832
|
+
let safestPerpTier = 4;
|
|
3833
|
+
let safestSpotTier = 4;
|
|
3834
|
+
|
|
3835
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
3836
|
+
safestPerpTier = Math.min(
|
|
3837
|
+
safestPerpTier,
|
|
3838
|
+
getPerpMarketTierNumber(
|
|
3839
|
+
this.driftClient.getPerpMarketAccount(perpPosition.marketIndex)
|
|
3840
|
+
)
|
|
3841
|
+
);
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
3845
|
+
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
3846
|
+
continue;
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
safestSpotTier = Math.min(
|
|
3850
|
+
safestSpotTier,
|
|
3851
|
+
getSpotMarketTierNumber(
|
|
3852
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex)
|
|
3853
|
+
)
|
|
3854
|
+
);
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
return {
|
|
3858
|
+
perpTier: safestPerpTier,
|
|
3859
|
+
spotTier: safestSpotTier,
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
|
|
3863
|
+
public getPerpPositionHealth({
|
|
3864
|
+
marginCategory,
|
|
3865
|
+
perpPosition,
|
|
3866
|
+
oraclePriceData,
|
|
3867
|
+
quoteOraclePriceData,
|
|
3868
|
+
includeOpenOrders = true,
|
|
3869
|
+
}: {
|
|
3870
|
+
marginCategory: MarginCategory;
|
|
3871
|
+
perpPosition: PerpPosition;
|
|
3872
|
+
oraclePriceData?: OraclePriceData;
|
|
3873
|
+
quoteOraclePriceData?: OraclePriceData;
|
|
3874
|
+
includeOpenOrders?: boolean;
|
|
3875
|
+
}): HealthComponent {
|
|
3876
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
3877
|
+
perpPosition.marketIndex
|
|
3878
|
+
);
|
|
3879
|
+
const _oraclePriceData =
|
|
3880
|
+
oraclePriceData ||
|
|
3881
|
+
this.driftClient.getOracleDataForPerpMarket(perpMarket.marketIndex);
|
|
3882
|
+
const oraclePrice = _oraclePriceData.price;
|
|
3883
|
+
|
|
3884
|
+
let worstCaseBaseAmount;
|
|
3885
|
+
let worstCaseLiabilityValue;
|
|
3886
|
+
if (includeOpenOrders) {
|
|
3887
|
+
const worstCaseIncludeOrders = calculateWorstCasePerpLiabilityValue(
|
|
3888
|
+
perpPosition,
|
|
3889
|
+
perpMarket,
|
|
3890
|
+
oraclePrice
|
|
3891
|
+
);
|
|
3892
|
+
worstCaseBaseAmount = worstCaseIncludeOrders.worstCaseBaseAssetAmount;
|
|
3893
|
+
worstCaseLiabilityValue = worstCaseIncludeOrders.worstCaseLiabilityValue;
|
|
3894
|
+
} else {
|
|
3895
|
+
worstCaseBaseAmount = perpPosition.baseAssetAmount;
|
|
3896
|
+
worstCaseLiabilityValue = calculatePerpLiabilityValue(
|
|
3897
|
+
perpPosition.baseAssetAmount,
|
|
3898
|
+
oraclePrice
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
|
|
3902
|
+
const userCustomMargin = Math.max(
|
|
3903
|
+
perpPosition.maxMarginRatio,
|
|
3904
|
+
this.getUserAccount().maxMarginRatio
|
|
3905
|
+
);
|
|
3906
|
+
const marginRatio = new BN(
|
|
3907
|
+
calculateMarketMarginRatio(
|
|
3908
|
+
perpMarket,
|
|
3909
|
+
worstCaseBaseAmount.abs(),
|
|
3910
|
+
marginCategory,
|
|
3911
|
+
userCustomMargin
|
|
3912
|
+
)
|
|
3913
|
+
);
|
|
3914
|
+
|
|
3915
|
+
const _quoteOraclePriceData =
|
|
3916
|
+
quoteOraclePriceData ||
|
|
3917
|
+
this.driftClient.getOracleDataForSpotMarket(QUOTE_SPOT_MARKET_INDEX);
|
|
3918
|
+
|
|
3919
|
+
let marginRequirement = worstCaseLiabilityValue
|
|
3920
|
+
.mul(_quoteOraclePriceData.price)
|
|
3921
|
+
.div(PRICE_PRECISION)
|
|
3922
|
+
.mul(marginRatio)
|
|
3923
|
+
.div(MARGIN_PRECISION);
|
|
3924
|
+
|
|
3925
|
+
marginRequirement = marginRequirement.add(
|
|
3926
|
+
new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
3927
|
+
);
|
|
3928
|
+
|
|
3929
|
+
return {
|
|
3930
|
+
marketIndex: perpMarket.marketIndex,
|
|
3931
|
+
size: worstCaseBaseAmount,
|
|
3932
|
+
value: worstCaseLiabilityValue,
|
|
3933
|
+
weight: marginRatio,
|
|
3934
|
+
weightedValue: marginRequirement,
|
|
3935
|
+
};
|
|
3936
|
+
}
|
|
3937
|
+
|
|
3938
|
+
public getHealthComponents({
|
|
3939
|
+
marginCategory,
|
|
3940
|
+
}: {
|
|
3941
|
+
marginCategory: MarginCategory;
|
|
3942
|
+
}): HealthComponents {
|
|
3943
|
+
const healthComponents: HealthComponents = {
|
|
3944
|
+
deposits: [],
|
|
3945
|
+
borrows: [],
|
|
3946
|
+
perpPositions: [],
|
|
3947
|
+
perpPnl: [],
|
|
3948
|
+
};
|
|
3949
|
+
|
|
3950
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
3951
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
3952
|
+
perpPosition.marketIndex
|
|
3953
|
+
);
|
|
3954
|
+
|
|
3955
|
+
const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(
|
|
3956
|
+
perpMarket.marketIndex
|
|
3957
|
+
);
|
|
3958
|
+
|
|
3959
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(
|
|
3960
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
3961
|
+
);
|
|
3962
|
+
|
|
3963
|
+
healthComponents.perpPositions.push(
|
|
3964
|
+
this.getPerpPositionHealth({
|
|
3965
|
+
marginCategory,
|
|
3966
|
+
perpPosition,
|
|
3967
|
+
oraclePriceData,
|
|
3968
|
+
quoteOraclePriceData,
|
|
3969
|
+
})
|
|
3970
|
+
);
|
|
3971
|
+
|
|
3972
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
3973
|
+
perpMarket.quoteSpotMarketIndex
|
|
3974
|
+
);
|
|
3975
|
+
|
|
3976
|
+
const positionUnrealizedPnl = calculatePositionPNL(
|
|
3977
|
+
perpMarket,
|
|
3978
|
+
perpPosition,
|
|
3979
|
+
true,
|
|
3980
|
+
oraclePriceData
|
|
3981
|
+
);
|
|
3982
|
+
|
|
3983
|
+
let pnlWeight;
|
|
3984
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
3985
|
+
pnlWeight = calculateUnrealizedAssetWeight(
|
|
3986
|
+
perpMarket,
|
|
3987
|
+
quoteSpotMarket,
|
|
3988
|
+
positionUnrealizedPnl,
|
|
3989
|
+
marginCategory,
|
|
3990
|
+
oraclePriceData
|
|
3991
|
+
);
|
|
3992
|
+
} else {
|
|
3993
|
+
pnlWeight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
3994
|
+
}
|
|
3995
|
+
|
|
3996
|
+
const pnlValue = positionUnrealizedPnl
|
|
3997
|
+
.mul(quoteOraclePriceData.price)
|
|
3998
|
+
.div(PRICE_PRECISION);
|
|
3999
|
+
|
|
4000
|
+
const wegithedPnlValue = pnlValue
|
|
4001
|
+
.mul(pnlWeight)
|
|
4002
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
4003
|
+
|
|
4004
|
+
healthComponents.perpPnl.push({
|
|
4005
|
+
marketIndex: perpMarket.marketIndex,
|
|
4006
|
+
size: positionUnrealizedPnl,
|
|
4007
|
+
value: pnlValue,
|
|
4008
|
+
weight: pnlWeight,
|
|
4009
|
+
weightedValue: wegithedPnlValue,
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
|
|
4013
|
+
let netQuoteValue = ZERO;
|
|
4014
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
4015
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
4016
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
4017
|
+
|
|
4018
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
4019
|
+
spotPosition.marketIndex
|
|
4020
|
+
);
|
|
4021
|
+
|
|
4022
|
+
const strictOraclePrice = new StrictOraclePrice(oraclePriceData.price);
|
|
4023
|
+
|
|
4024
|
+
if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
4025
|
+
const tokenAmount = getSignedTokenAmount(
|
|
4026
|
+
getTokenAmount(
|
|
4027
|
+
spotPosition.scaledBalance,
|
|
4028
|
+
spotMarketAccount,
|
|
4029
|
+
spotPosition.balanceType
|
|
4030
|
+
),
|
|
4031
|
+
spotPosition.balanceType
|
|
4032
|
+
);
|
|
4033
|
+
|
|
4034
|
+
netQuoteValue = netQuoteValue.add(tokenAmount);
|
|
4035
|
+
continue;
|
|
4036
|
+
}
|
|
4037
|
+
|
|
4038
|
+
const {
|
|
4039
|
+
tokenAmount: worstCaseTokenAmount,
|
|
4040
|
+
tokenValue: tokenValue,
|
|
4041
|
+
weight,
|
|
4042
|
+
weightedTokenValue: weightedTokenValue,
|
|
4043
|
+
ordersValue: ordersValue,
|
|
4044
|
+
} = getWorstCaseTokenAmounts(
|
|
4045
|
+
spotPosition,
|
|
4046
|
+
spotMarketAccount,
|
|
4047
|
+
strictOraclePrice,
|
|
4048
|
+
marginCategory,
|
|
4049
|
+
this.getUserAccount().maxMarginRatio
|
|
4050
|
+
);
|
|
4051
|
+
|
|
4052
|
+
netQuoteValue = netQuoteValue.add(ordersValue);
|
|
4053
|
+
|
|
4054
|
+
const baseAssetValue = tokenValue.abs();
|
|
4055
|
+
const weightedValue = weightedTokenValue.abs();
|
|
4056
|
+
|
|
4057
|
+
if (weightedTokenValue.lt(ZERO)) {
|
|
4058
|
+
healthComponents.borrows.push({
|
|
4059
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
4060
|
+
size: worstCaseTokenAmount,
|
|
4061
|
+
value: baseAssetValue,
|
|
4062
|
+
weight: weight,
|
|
4063
|
+
weightedValue: weightedValue,
|
|
4064
|
+
});
|
|
4065
|
+
} else {
|
|
4066
|
+
healthComponents.deposits.push({
|
|
4067
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
4068
|
+
size: worstCaseTokenAmount,
|
|
4069
|
+
value: baseAssetValue,
|
|
4070
|
+
weight: weight,
|
|
4071
|
+
weightedValue: weightedValue,
|
|
4072
|
+
});
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
|
|
4076
|
+
if (!netQuoteValue.eq(ZERO)) {
|
|
4077
|
+
const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
|
|
4078
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
4079
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
4080
|
+
);
|
|
4081
|
+
|
|
4082
|
+
const baseAssetValue = getTokenValue(
|
|
4083
|
+
netQuoteValue,
|
|
4084
|
+
spotMarketAccount.decimals,
|
|
4085
|
+
oraclePriceData
|
|
4086
|
+
);
|
|
4087
|
+
|
|
4088
|
+
const { weight, weightedTokenValue } = calculateWeightedTokenValue(
|
|
4089
|
+
netQuoteValue,
|
|
4090
|
+
baseAssetValue,
|
|
4091
|
+
oraclePriceData.price,
|
|
4092
|
+
spotMarketAccount,
|
|
4093
|
+
marginCategory,
|
|
4094
|
+
this.getUserAccount().maxMarginRatio
|
|
4095
|
+
);
|
|
4096
|
+
|
|
4097
|
+
if (netQuoteValue.lt(ZERO)) {
|
|
4098
|
+
healthComponents.borrows.push({
|
|
4099
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
4100
|
+
size: netQuoteValue,
|
|
4101
|
+
value: baseAssetValue.abs(),
|
|
4102
|
+
weight: weight,
|
|
4103
|
+
weightedValue: weightedTokenValue.abs(),
|
|
4104
|
+
});
|
|
4105
|
+
} else {
|
|
4106
|
+
healthComponents.deposits.push({
|
|
4107
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
4108
|
+
size: netQuoteValue,
|
|
4109
|
+
value: baseAssetValue,
|
|
4110
|
+
weight: weight,
|
|
4111
|
+
weightedValue: weightedTokenValue,
|
|
4112
|
+
});
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
return healthComponents;
|
|
4117
|
+
}
|
|
4118
|
+
|
|
4119
|
+
/**
|
|
4120
|
+
* Get the total position value, excluding any position coming from the given target market
|
|
4121
|
+
* @param marketToIgnore
|
|
4122
|
+
* @returns positionValue : Precision QUOTE_PRECISION
|
|
4123
|
+
*/
|
|
4124
|
+
private getTotalPerpPositionValueExcludingMarket(
|
|
4125
|
+
marketToIgnore: number,
|
|
4126
|
+
marginCategory?: MarginCategory,
|
|
4127
|
+
liquidationBuffer?: BN,
|
|
4128
|
+
includeOpenOrders?: boolean
|
|
4129
|
+
): BN {
|
|
4130
|
+
const currentPerpPosition = this.getPerpPositionOrEmpty(marketToIgnore);
|
|
4131
|
+
|
|
4132
|
+
const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
|
|
4133
|
+
|
|
4134
|
+
let currentPerpPositionValueUSDC = ZERO;
|
|
4135
|
+
if (currentPerpPosition) {
|
|
4136
|
+
currentPerpPositionValueUSDC = this.getPerpLiabilityValue(
|
|
4137
|
+
marketToIgnore,
|
|
4138
|
+
oracleData,
|
|
4139
|
+
includeOpenOrders
|
|
4140
|
+
);
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
return this.getTotalPerpPositionLiability(
|
|
4144
|
+
marginCategory,
|
|
4145
|
+
liquidationBuffer,
|
|
4146
|
+
includeOpenOrders
|
|
4147
|
+
).sub(currentPerpPositionValueUSDC);
|
|
4148
|
+
}
|
|
4149
|
+
|
|
4150
|
+
private getMMOracleDataForPerpMarket(marketIndex: number): MMOraclePriceData {
|
|
4151
|
+
return this.driftClient.getMMOracleDataForPerpMarket(marketIndex);
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
private getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
|
|
4155
|
+
return this.driftClient.getOracleDataForPerpMarket(marketIndex);
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
private getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
|
|
4159
|
+
return this.driftClient.getOracleDataForSpotMarket(marketIndex);
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
/**
|
|
4163
|
+
* Get the active perp and spot positions of the user.
|
|
4164
|
+
*/
|
|
4165
|
+
public getActivePositions(): {
|
|
4166
|
+
activePerpPositions: number[];
|
|
4167
|
+
activeSpotPositions: number[];
|
|
4168
|
+
} {
|
|
4169
|
+
const activePerpMarkets = this.getActivePerpPositions().map(
|
|
4170
|
+
(position) => position.marketIndex
|
|
4171
|
+
);
|
|
4172
|
+
|
|
4173
|
+
const activeSpotMarkets = this.getActiveSpotPositions().map(
|
|
4174
|
+
(position) => position.marketIndex
|
|
4175
|
+
);
|
|
4176
|
+
|
|
4177
|
+
return {
|
|
4178
|
+
activePerpPositions: activePerpMarkets,
|
|
4179
|
+
activeSpotPositions: activeSpotMarkets,
|
|
4180
|
+
};
|
|
4181
|
+
}
|
|
4182
|
+
|
|
4183
|
+
/**
|
|
4184
|
+
* Compute the full margin calculation for the user's account.
|
|
4185
|
+
* Prioritize using this function instead of calling getMarginRequirement or getTotalCollateral multiple times.
|
|
4186
|
+
* Consumers can use this to avoid duplicating work across separate calls.
|
|
4187
|
+
*/
|
|
4188
|
+
public getMarginCalculation(
|
|
4189
|
+
marginCategory: MarginCategory = 'Initial',
|
|
4190
|
+
opts?: {
|
|
4191
|
+
strict?: boolean; // mirror StrictOraclePrice application
|
|
4192
|
+
includeOpenOrders?: boolean;
|
|
4193
|
+
liquidationBufferMap?: Map<number | 'cross', BN>; // margin_buffer analog for buffer mode
|
|
4194
|
+
}
|
|
4195
|
+
): MarginCalculation {
|
|
4196
|
+
const strict = opts?.strict ?? false;
|
|
4197
|
+
const liquidationBufferMap = opts?.liquidationBufferMap ?? new Map();
|
|
4198
|
+
const includeOpenOrders = opts?.includeOpenOrders ?? true;
|
|
4199
|
+
|
|
4200
|
+
// Equivalent to on-chain user_custom_margin_ratio
|
|
4201
|
+
const userCustomMarginRatio =
|
|
4202
|
+
marginCategory === 'Initial' ? this.getUserAccount().maxMarginRatio : 0;
|
|
4203
|
+
|
|
4204
|
+
// Initialize calc via JS mirror of Rust/on-chain MarginCalculation
|
|
4205
|
+
const isolatedMarginBuffers = new Map<number, BN>();
|
|
4206
|
+
for (const [
|
|
4207
|
+
marketIndex,
|
|
4208
|
+
isolatedMarginBuffer,
|
|
4209
|
+
] of opts?.liquidationBufferMap ?? new Map()) {
|
|
4210
|
+
if (marketIndex !== 'cross') {
|
|
4211
|
+
isolatedMarginBuffers.set(marketIndex, isolatedMarginBuffer);
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
const ctx = MarginContext.standard(marginCategory)
|
|
4215
|
+
.strictMode(strict)
|
|
4216
|
+
.setCrossMarginBuffer(opts?.liquidationBufferMap?.get('cross') ?? ZERO)
|
|
4217
|
+
.setIsolatedMarginBuffers(isolatedMarginBuffers);
|
|
4218
|
+
const calc = new MarginCalculation(ctx);
|
|
4219
|
+
|
|
4220
|
+
// SPOT POSITIONS
|
|
4221
|
+
for (const spotPosition of this.getUserAccount().spotPositions) {
|
|
4222
|
+
if (isSpotPositionAvailable(spotPosition)) continue;
|
|
4223
|
+
|
|
4224
|
+
const isQuote = spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX;
|
|
4225
|
+
|
|
4226
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(
|
|
4227
|
+
spotPosition.marketIndex
|
|
4228
|
+
);
|
|
4229
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
4230
|
+
spotPosition.marketIndex
|
|
4231
|
+
);
|
|
4232
|
+
const twap5 = strict
|
|
4233
|
+
? calculateLiveOracleTwap(
|
|
4234
|
+
spotMarket.historicalOracleData,
|
|
4235
|
+
oraclePriceData,
|
|
4236
|
+
new BN(Math.floor(Date.now() / 1000)),
|
|
4237
|
+
FIVE_MINUTE
|
|
4238
|
+
)
|
|
4239
|
+
: undefined;
|
|
4240
|
+
const strictOracle = new StrictOraclePrice(oraclePriceData.price, twap5);
|
|
4241
|
+
|
|
4242
|
+
if (isQuote) {
|
|
4243
|
+
const tokenAmount = getSignedTokenAmount(
|
|
4244
|
+
getTokenAmount(
|
|
4245
|
+
spotPosition.scaledBalance,
|
|
4246
|
+
spotMarket,
|
|
4247
|
+
spotPosition.balanceType
|
|
4248
|
+
),
|
|
4249
|
+
spotPosition.balanceType
|
|
4250
|
+
);
|
|
4251
|
+
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
4252
|
+
// add deposit value to total collateral
|
|
4253
|
+
const weightedTokenValue = this.getSpotAssetValue(
|
|
4254
|
+
tokenAmount,
|
|
4255
|
+
strictOracle,
|
|
4256
|
+
spotMarket,
|
|
4257
|
+
marginCategory
|
|
4258
|
+
);
|
|
4259
|
+
calc.addCrossMarginTotalCollateral(weightedTokenValue);
|
|
4260
|
+
} else {
|
|
4261
|
+
// borrow on quote contributes to margin requirement
|
|
4262
|
+
const tokenValueAbs = this.getSpotLiabilityValue(
|
|
4263
|
+
tokenAmount,
|
|
4264
|
+
strictOracle,
|
|
4265
|
+
spotMarket,
|
|
4266
|
+
marginCategory,
|
|
4267
|
+
liquidationBufferMap.get('cross') ?? new BN(0)
|
|
4268
|
+
).abs();
|
|
4269
|
+
calc.addCrossMarginRequirement(tokenValueAbs, tokenValueAbs);
|
|
4270
|
+
}
|
|
4271
|
+
continue;
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
// Non-quote spot: worst-case simulation
|
|
4275
|
+
const {
|
|
4276
|
+
tokenAmount: worstCaseTokenAmount,
|
|
4277
|
+
ordersValue: worstCaseOrdersValue,
|
|
4278
|
+
} = getWorstCaseTokenAmounts(
|
|
4279
|
+
spotPosition,
|
|
4280
|
+
spotMarket,
|
|
4281
|
+
strictOracle,
|
|
4282
|
+
marginCategory,
|
|
4283
|
+
userCustomMarginRatio,
|
|
4284
|
+
includeOpenOrders
|
|
4285
|
+
// false
|
|
4286
|
+
);
|
|
4287
|
+
|
|
4288
|
+
if (includeOpenOrders) {
|
|
4289
|
+
// open order IM
|
|
4290
|
+
calc.addCrossMarginRequirement(
|
|
4291
|
+
new BN(spotPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT),
|
|
4292
|
+
ZERO
|
|
4293
|
+
);
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
if (worstCaseTokenAmount.gt(ZERO)) {
|
|
4297
|
+
const baseAssetValue = this.getSpotAssetValue(
|
|
4298
|
+
worstCaseTokenAmount,
|
|
4299
|
+
strictOracle,
|
|
4300
|
+
spotMarket,
|
|
4301
|
+
marginCategory
|
|
4302
|
+
);
|
|
4303
|
+
// asset side increases total collateral (weighted)
|
|
4304
|
+
calc.addCrossMarginTotalCollateral(baseAssetValue);
|
|
4305
|
+
} else if (worstCaseTokenAmount.lt(ZERO)) {
|
|
4306
|
+
// liability side increases margin requirement (weighted >= abs(token_value))
|
|
4307
|
+
const getSpotLiabilityValue = this.getSpotLiabilityValue(
|
|
4308
|
+
worstCaseTokenAmount,
|
|
4309
|
+
strictOracle,
|
|
4310
|
+
spotMarket,
|
|
4311
|
+
marginCategory,
|
|
4312
|
+
liquidationBufferMap.get('cross')
|
|
4313
|
+
);
|
|
4314
|
+
|
|
4315
|
+
calc.addCrossMarginRequirement(
|
|
4316
|
+
getSpotLiabilityValue.abs(),
|
|
4317
|
+
getSpotLiabilityValue.abs()
|
|
4318
|
+
);
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4321
|
+
// orders value contributes to collateral or requirement
|
|
4322
|
+
if (worstCaseOrdersValue.gt(ZERO)) {
|
|
4323
|
+
calc.addCrossMarginTotalCollateral(worstCaseOrdersValue);
|
|
4324
|
+
} else if (worstCaseOrdersValue.lt(ZERO)) {
|
|
4325
|
+
const absVal = worstCaseOrdersValue.abs();
|
|
4326
|
+
calc.addCrossMarginRequirement(absVal, absVal);
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
// PERP POSITIONS
|
|
4331
|
+
for (const marketPosition of this.getActivePerpPositions()) {
|
|
4332
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
4333
|
+
marketPosition.marketIndex
|
|
4334
|
+
);
|
|
4335
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
4336
|
+
market.quoteSpotMarketIndex
|
|
4337
|
+
);
|
|
4338
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(
|
|
4339
|
+
market.quoteSpotMarketIndex
|
|
4340
|
+
);
|
|
4341
|
+
const oraclePriceData = this.getMMOracleDataForPerpMarket(
|
|
4342
|
+
market.marketIndex
|
|
4343
|
+
);
|
|
4344
|
+
|
|
4345
|
+
const nonMmmOraclePriceData = this.getOracleDataForPerpMarket(
|
|
4346
|
+
market.marketIndex
|
|
4347
|
+
);
|
|
4348
|
+
|
|
4349
|
+
// Worst-case perp liability and weighted pnl
|
|
4350
|
+
const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
|
|
4351
|
+
calculateWorstCasePerpLiabilityValue(
|
|
4352
|
+
marketPosition,
|
|
4353
|
+
market,
|
|
4354
|
+
nonMmmOraclePriceData.price,
|
|
4355
|
+
includeOpenOrders
|
|
4356
|
+
);
|
|
4357
|
+
|
|
4358
|
+
// margin ratio for this perp
|
|
4359
|
+
const customMarginRatio = Math.max(
|
|
4360
|
+
userCustomMarginRatio,
|
|
4361
|
+
marketPosition.maxMarginRatio
|
|
4362
|
+
);
|
|
4363
|
+
let marginRatio = new BN(
|
|
4364
|
+
calculateMarketMarginRatio(
|
|
4365
|
+
market,
|
|
4366
|
+
worstCaseBaseAssetAmount.abs(),
|
|
4367
|
+
marginCategory,
|
|
4368
|
+
customMarginRatio
|
|
4369
|
+
)
|
|
4370
|
+
);
|
|
4371
|
+
if (isVariant(market.status, 'settlement')) {
|
|
4372
|
+
marginRatio = ZERO;
|
|
4373
|
+
}
|
|
4374
|
+
|
|
4375
|
+
// convert liability to quote value and apply margin ratio
|
|
4376
|
+
const quotePrice = strict
|
|
4377
|
+
? BN.max(
|
|
4378
|
+
quoteOraclePriceData.price,
|
|
4379
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
4380
|
+
)
|
|
4381
|
+
: quoteOraclePriceData.price;
|
|
4382
|
+
let perpMarginRequirement = worstCaseLiabilityValue
|
|
4383
|
+
.mul(quotePrice)
|
|
4384
|
+
.div(PRICE_PRECISION)
|
|
4385
|
+
.mul(marginRatio)
|
|
4386
|
+
.div(MARGIN_PRECISION);
|
|
4387
|
+
// add open orders IM
|
|
4388
|
+
if (includeOpenOrders) {
|
|
4389
|
+
perpMarginRequirement = perpMarginRequirement.add(
|
|
4390
|
+
new BN(marketPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
4391
|
+
);
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
// weighted unrealized pnl
|
|
4395
|
+
let positionUnrealizedPnl = calculatePositionPNL(
|
|
4396
|
+
market,
|
|
4397
|
+
marketPosition,
|
|
4398
|
+
true,
|
|
4399
|
+
oraclePriceData
|
|
4400
|
+
);
|
|
4401
|
+
let pnlQuotePrice: BN;
|
|
4402
|
+
if (strict && positionUnrealizedPnl.gt(ZERO)) {
|
|
4403
|
+
pnlQuotePrice = BN.min(
|
|
4404
|
+
quoteOraclePriceData.price,
|
|
4405
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
4406
|
+
);
|
|
4407
|
+
} else if (strict && positionUnrealizedPnl.lt(ZERO)) {
|
|
4408
|
+
pnlQuotePrice = BN.max(
|
|
4409
|
+
quoteOraclePriceData.price,
|
|
4410
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
4411
|
+
);
|
|
4412
|
+
} else {
|
|
4413
|
+
pnlQuotePrice = quoteOraclePriceData.price;
|
|
4414
|
+
}
|
|
4415
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
4416
|
+
.mul(pnlQuotePrice)
|
|
4417
|
+
.div(PRICE_PRECISION);
|
|
4418
|
+
|
|
4419
|
+
if (marginCategory !== undefined) {
|
|
4420
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
4421
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
4422
|
+
.mul(
|
|
4423
|
+
calculateUnrealizedAssetWeight(
|
|
4424
|
+
market,
|
|
4425
|
+
quoteSpotMarket,
|
|
4426
|
+
positionUnrealizedPnl,
|
|
4427
|
+
marginCategory,
|
|
4428
|
+
oraclePriceData
|
|
4429
|
+
)
|
|
4430
|
+
)
|
|
4431
|
+
.div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
|
|
4435
|
+
// Add perp contribution: isolated vs cross
|
|
4436
|
+
const isIsolated = this.isPerpPositionIsolated(marketPosition);
|
|
4437
|
+
if (isIsolated) {
|
|
4438
|
+
// derive isolated quote deposit value, mirroring on-chain logic
|
|
4439
|
+
let depositValue = ZERO;
|
|
4440
|
+
if (marketPosition.isolatedPositionScaledBalance?.gt(ZERO)) {
|
|
4441
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
4442
|
+
market.quoteSpotMarketIndex
|
|
4443
|
+
);
|
|
4444
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(
|
|
4445
|
+
market.quoteSpotMarketIndex
|
|
4446
|
+
);
|
|
4447
|
+
const strictQuote = new StrictOraclePrice(
|
|
4448
|
+
quoteOraclePriceData.price,
|
|
4449
|
+
strict
|
|
4450
|
+
? quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
4451
|
+
: undefined
|
|
4452
|
+
);
|
|
4453
|
+
const quoteTokenAmount = getTokenAmount(
|
|
4454
|
+
marketPosition.isolatedPositionScaledBalance ?? ZERO,
|
|
4455
|
+
quoteSpotMarket,
|
|
4456
|
+
SpotBalanceType.DEPOSIT
|
|
4457
|
+
);
|
|
4458
|
+
depositValue = getStrictTokenValue(
|
|
4459
|
+
quoteTokenAmount,
|
|
4460
|
+
quoteSpotMarket.decimals,
|
|
4461
|
+
strictQuote
|
|
4462
|
+
);
|
|
4463
|
+
}
|
|
4464
|
+
calc.addIsolatedMarginCalculation(
|
|
4465
|
+
market.marketIndex,
|
|
4466
|
+
depositValue,
|
|
4467
|
+
positionUnrealizedPnl,
|
|
4468
|
+
worstCaseLiabilityValue,
|
|
4469
|
+
perpMarginRequirement
|
|
4470
|
+
);
|
|
4471
|
+
calc.addPerpLiabilityValue(worstCaseLiabilityValue);
|
|
4472
|
+
} else {
|
|
4473
|
+
// cross: add to global requirement and collateral
|
|
4474
|
+
calc.addCrossMarginRequirement(
|
|
4475
|
+
perpMarginRequirement,
|
|
4476
|
+
worstCaseLiabilityValue
|
|
4477
|
+
);
|
|
4478
|
+
calc.addCrossMarginTotalCollateral(positionUnrealizedPnl);
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
return calc;
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
public isPerpPositionIsolated(perpPosition: PerpPosition): boolean {
|
|
4485
|
+
return (perpPosition.positionFlag & PositionFlag.IsolatedPosition) !== 0;
|
|
4486
|
+
}
|
|
4487
|
+
}
|