@velocity-exchange/sdk 0.4.0 → 0.6.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/README.md +3 -3
- package/lib/browser/adminClient.d.ts +52 -0
- package/lib/browser/adminClient.js +97 -0
- package/lib/browser/config.js +6 -7
- package/lib/browser/constants/numericConstants.d.ts +1 -1
- package/lib/browser/constants/numericConstants.js +1 -1
- package/lib/browser/decode/user.js +5 -1
- package/lib/browser/idl/velocity.d.ts +191 -15
- package/lib/browser/idl/velocity.json +192 -16
- package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +1 -0
- package/lib/browser/orderSubscriber/OrderSubscriber.js +10 -4
- package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
- package/lib/browser/types.d.ts +6 -0
- package/lib/browser/user.d.ts +20 -3
- package/lib/browser/user.js +52 -4
- package/lib/browser/velocityClient.d.ts +46 -10
- package/lib/browser/velocityClient.js +107 -35
- package/lib/node/adminClient.d.ts +52 -0
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +97 -0
- package/lib/node/config.d.ts.map +1 -1
- package/lib/node/config.js +6 -7
- package/lib/node/constants/numericConstants.d.ts +1 -1
- package/lib/node/constants/numericConstants.d.ts.map +1 -1
- package/lib/node/constants/numericConstants.js +1 -1
- package/lib/node/decode/user.d.ts.map +1 -1
- package/lib/node/decode/user.js +5 -1
- package/lib/node/idl/velocity.d.ts +191 -15
- package/lib/node/idl/velocity.d.ts.map +1 -1
- package/lib/node/idl/velocity.json +192 -16
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts +1 -0
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
- package/lib/node/orderSubscriber/OrderSubscriber.js +10 -4
- package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
- package/lib/node/pyth/pythLazerSubscriber.js +37 -27
- package/lib/node/types.d.ts +6 -0
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/user.d.ts +20 -3
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +52 -4
- package/lib/node/velocityClient.d.ts +46 -10
- package/lib/node/velocityClient.d.ts.map +1 -1
- package/lib/node/velocityClient.js +107 -35
- package/package.json +7 -3
- package/.prettierignore +0 -1
- package/CHANGELOG.md +0 -132
- package/build-browser.js +0 -58
- package/bunfig.toml +0 -3
- package/esbuild-shims.js +0 -12
- package/scripts/deposit-isolated-positions.ts +0 -110
- package/scripts/find-flagged-users.ts +0 -213
- package/scripts/grpc-client-test-comparison.ts +0 -372
- package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
- package/scripts/postbuild.js +0 -95
- package/scripts/single-grpc-client-test.ts +0 -284
- package/scripts/withdraw-isolated-positions.ts +0 -174
- package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
- package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
- package/src/accounts/basicUserAccountSubscriber.ts +0 -79
- package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -87
- package/src/accounts/bulkAccountLoader.ts +0 -358
- package/src/accounts/bulkUserStatsSubscription.ts +0 -40
- package/src/accounts/bulkUserSubscription.ts +0 -39
- package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -250
- package/src/accounts/fetch.ts +0 -200
- package/src/accounts/grpcAccountSubscriber.ts +0 -225
- package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -73
- package/src/accounts/grpcMultiAccountSubscriber.ts +0 -566
- package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -328
- package/src/accounts/grpcProgramAccountSubscriber.ts +0 -264
- package/src/accounts/grpcUserAccountSubscriber.ts +0 -63
- package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -65
- package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -257
- package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -941
- package/src/accounts/laserProgramAccountSubscriber.ts +0 -266
- package/src/accounts/oneShotUserAccountSubscriber.ts +0 -88
- package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -94
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -223
- package/src/accounts/pollingOracleAccountSubscriber.ts +0 -151
- package/src/accounts/pollingTokenAccountSubscriber.ts +0 -147
- package/src/accounts/pollingUserAccountSubscriber.ts +0 -198
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -180
- package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -774
- package/src/accounts/testBulkAccountLoader.ts +0 -59
- package/src/accounts/types.ts +0 -428
- package/src/accounts/utils.ts +0 -90
- package/src/accounts/webSocketAccountSubscriber.ts +0 -304
- package/src/accounts/webSocketAccountSubscriberV2.ts +0 -536
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -171
- package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -244
- package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1048
- package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1042
- package/src/accounts/webSocketUserAccountSubscriber.ts +0 -139
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -131
- package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -865
- package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -897
- package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -127
- package/src/addresses/marketAddresses.ts +0 -28
- package/src/addresses/pda.ts +0 -620
- package/src/adminClient.ts +0 -8136
- package/src/assert/assert.ts +0 -5
- package/src/auctionSubscriber/auctionSubscriber.ts +0 -86
- package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -99
- package/src/auctionSubscriber/index.ts +0 -9
- package/src/auctionSubscriber/types.ts +0 -30
- package/src/bankrun/bankrunConnection.ts +0 -630
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -160
- package/src/blockhashSubscriber/index.ts +0 -6
- package/src/blockhashSubscriber/types.ts +0 -13
- package/src/clock/clockSubscriber.ts +0 -146
- package/src/config.ts +0 -312
- package/src/constants/index.ts +0 -9
- package/src/constants/numericConstants.ts +0 -194
- package/src/constants/perpMarkets.ts +0 -127
- package/src/constants/spotMarkets.ts +0 -104
- package/src/constants/txConstants.ts +0 -2
- package/src/constituentMap/constituentMap.ts +0 -305
- package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
- package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
- package/src/core/VelocityCore.ts +0 -606
- package/src/core/index.ts +0 -12
- package/src/core/instructions/deposit.ts +0 -64
- package/src/core/instructions/fill.ts +0 -51
- package/src/core/instructions/funding.ts +0 -33
- package/src/core/instructions/liquidation.ts +0 -55
- package/src/core/instructions/orders.ts +0 -84
- package/src/core/instructions/perpOrders.ts +0 -312
- package/src/core/instructions/settlement.ts +0 -40
- package/src/core/instructions/trigger.ts +0 -41
- package/src/core/instructions/withdraw.ts +0 -65
- package/src/core/remainingAccounts.ts +0 -320
- package/src/core/signedMsg.ts +0 -109
- package/src/decode/customCoder.ts +0 -148
- package/src/decode/user.ts +0 -401
- package/src/dlob/DLOB.ts +0 -2793
- package/src/dlob/DLOBNode.ts +0 -305
- package/src/dlob/DLOBSubscriber.ts +0 -269
- package/src/dlob/NodeList.ts +0 -244
- package/src/dlob/orderBookLevels.ts +0 -695
- package/src/dlob/types.ts +0 -37
- package/src/events/eventList.ts +0 -114
- package/src/events/eventSubscriber.ts +0 -521
- package/src/events/eventsServerLogProvider.ts +0 -189
- package/src/events/fetchLogs.ts +0 -219
- package/src/events/parse.ts +0 -271
- package/src/events/pollingLogProvider.ts +0 -113
- package/src/events/sort.ts +0 -51
- package/src/events/txEventCache.ts +0 -92
- package/src/events/types.ts +0 -337
- package/src/events/webSocketLogProvider.ts +0 -152
- package/src/factory/bigNum.ts +0 -709
- package/src/factory/oracleClient.ts +0 -73
- package/src/idl/pyth.json +0 -142
- package/src/idl/pyth.ts +0 -97
- package/src/idl/pyth_solana_receiver.json +0 -628
- package/src/idl/token_faucet.json +0 -229
- package/src/idl/token_faucet.ts +0 -197
- package/src/idl/velocity.json +0 -23974
- package/src/idl/velocity.ts +0 -23980
- package/src/index.ts +0 -150
- package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
- package/src/isomorphic/README.md +0 -19
- package/src/isomorphic/anchor.browser.ts +0 -44
- package/src/isomorphic/anchor.node.ts +0 -1
- package/src/isomorphic/anchor.ts +0 -1
- package/src/isomorphic/anchor29.browser.ts +0 -24
- package/src/isomorphic/anchor29.node.ts +0 -1
- package/src/isomorphic/anchor29.ts +0 -1
- package/src/isomorphic/grpc.browser.ts +0 -4
- package/src/isomorphic/grpc.node.ts +0 -130
- package/src/isomorphic/grpc.ts +0 -1
- package/src/jupiter/jupiterClient.ts +0 -502
- package/src/keypair.ts +0 -32
- package/src/margin/README.md +0 -138
- package/src/marginCalculation.ts +0 -407
- package/src/marinade/idl/idl.json +0 -1962
- package/src/marinade/index.ts +0 -73
- package/src/marinade/types.ts +0 -3925
- package/src/math/amm.ts +0 -1758
- package/src/math/auction.ts +0 -480
- package/src/math/bankruptcy.ts +0 -138
- package/src/math/builder.ts +0 -130
- package/src/math/conversion.ts +0 -45
- package/src/math/exchangeStatus.ts +0 -261
- package/src/math/funding.ts +0 -498
- package/src/math/insurance.ts +0 -171
- package/src/math/liquidation.ts +0 -433
- package/src/math/margin.ts +0 -327
- package/src/math/market.ts +0 -487
- package/src/math/oracles.ts +0 -477
- package/src/math/orders.ts +0 -500
- package/src/math/position.ts +0 -381
- package/src/math/repeg.ts +0 -223
- package/src/math/spotBalance.ts +0 -996
- package/src/math/spotMarket.ts +0 -115
- package/src/math/spotPosition.ts +0 -263
- package/src/math/state.ts +0 -71
- package/src/math/superStake.ts +0 -602
- package/src/math/tiers.ts +0 -73
- package/src/math/trade.ts +0 -879
- package/src/math/utils.ts +0 -183
- package/src/memcmp.ts +0 -279
- package/src/oracles/oracleClientCache.ts +0 -41
- package/src/oracles/oracleId.ts +0 -99
- package/src/oracles/prelaunchOracleClient.ts +0 -63
- package/src/oracles/pythClient.ts +0 -125
- package/src/oracles/pythLazerClient.ts +0 -141
- package/src/oracles/quoteAssetOracleClient.ts +0 -43
- package/src/oracles/strictOraclePrice.ts +0 -40
- package/src/oracles/types.ts +0 -82
- package/src/oracles/utils.ts +0 -45
- package/src/orderParams.ts +0 -117
- package/src/orderSubscriber/OrderSubscriber.ts +0 -378
- package/src/orderSubscriber/PollingSubscription.ts +0 -50
- package/src/orderSubscriber/WebsocketSubscription.ts +0 -137
- package/src/orderSubscriber/grpcSubscription.ts +0 -155
- package/src/orderSubscriber/index.ts +0 -7
- package/src/orderSubscriber/types.ts +0 -64
- package/src/priorityFee/averageOverSlotsStrategy.ts +0 -17
- package/src/priorityFee/averageStrategy.ts +0 -13
- package/src/priorityFee/ewmaStrategy.ts +0 -51
- package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -68
- package/src/priorityFee/index.ts +0 -16
- package/src/priorityFee/maxOverSlotsStrategy.ts +0 -18
- package/src/priorityFee/maxStrategy.ts +0 -8
- package/src/priorityFee/priorityFeeSubscriber.ts +0 -328
- package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -134
- package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -46
- package/src/priorityFee/types.ts +0 -82
- package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -53
- package/src/pyth/constants.ts +0 -9
- package/src/pyth/index.ts +0 -15
- package/src/pyth/pythLazerSubscriber.ts +0 -365
- package/src/pyth/types.ts +0 -4451
- package/src/pyth/utils.ts +0 -13
- package/src/slot/SlotSubscriber.ts +0 -126
- package/src/slot/SlothashSubscriber.ts +0 -163
- package/src/swap/UnifiedSwapClient.ts +0 -315
- package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
- package/src/swift/index.ts +0 -10
- package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
- package/src/swift/swiftOrderSubscriber.ts +0 -351
- package/src/testClient.ts +0 -42
- package/src/titan/titanClient.ts +0 -438
- package/src/token/index.ts +0 -13
- package/src/tokenFaucet.ts +0 -296
- package/src/tx/baseTxSender.ts +0 -651
- package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -31
- package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -105
- package/src/tx/blockhashFetcher/types.ts +0 -9
- package/src/tx/fastSingleTxSender.ts +0 -200
- package/src/tx/forwardOnlyTxSender.ts +0 -193
- package/src/tx/priorityFeeCalculator.ts +0 -117
- package/src/tx/reportTransactionError.ts +0 -176
- package/src/tx/retryTxSender.ts +0 -177
- package/src/tx/txHandler.ts +0 -1009
- package/src/tx/txParamProcessor.ts +0 -225
- package/src/tx/types.ts +0 -117
- package/src/tx/utils.ts +0 -133
- package/src/tx/whileValidTxSender.ts +0 -377
- package/src/types.ts +0 -2575
- package/src/user.ts +0 -5316
- package/src/userConfig.ts +0 -38
- package/src/userMap/PollingSubscription.ts +0 -61
- package/src/userMap/WebsocketSubscription.ts +0 -93
- package/src/userMap/grpcSubscription.ts +0 -93
- package/src/userMap/referrerMap.ts +0 -360
- package/src/userMap/revenueShareEscrowMap.ts +0 -342
- package/src/userMap/userMap.ts +0 -784
- package/src/userMap/userMapConfig.ts +0 -82
- package/src/userMap/userStatsMap.ts +0 -393
- package/src/userName.ts +0 -37
- package/src/userStats.ts +0 -159
- package/src/userStatsConfig.ts +0 -35
- package/src/util/TransactionConfirmationManager.ts +0 -333
- package/src/util/chainClock.ts +0 -65
- package/src/util/computeUnits.ts +0 -101
- package/src/util/digest.ts +0 -33
- package/src/util/ed25519Utils.ts +0 -95
- package/src/util/promiseTimeout.ts +0 -23
- package/src/velocityClient.ts +0 -14802
- package/src/velocityClientConfig.ts +0 -119
- package/src/wallet.ts +0 -91
- package/tests/VelocityCore/builder_escrow.test.ts +0 -121
- package/tests/VelocityCore/decode.test.ts +0 -16
- package/tests/VelocityCore/fill_trigger.test.ts +0 -73
- package/tests/VelocityCore/instructions.test.ts +0 -46
- package/tests/VelocityCore/pdas.test.ts +0 -30
- package/tests/VelocityCore/perp_orders.test.ts +0 -205
- package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
- package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
- package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
- package/tests/amm/test.ts +0 -2402
- package/tests/auctions/test.ts +0 -81
- package/tests/bn/test.ts +0 -355
- package/tests/builder/builderFee.test.ts +0 -42
- package/tests/ci/verifyConstants.ts +0 -393
- package/tests/decode/test.ts +0 -262
- package/tests/decode/userAccountBufferStrings.ts +0 -102
- package/tests/dlob/helpers.ts +0 -748
- package/tests/dlob/test.ts +0 -6969
- package/tests/dlob/tickSizeStandardization.ts +0 -545
- package/tests/events/parseLogsForCuUsage.ts +0 -139
- package/tests/exchangeStatus/test.ts +0 -45
- package/tests/insurance/test.ts +0 -40
- package/tests/liquidation/test.ts +0 -125
- package/tests/oracles/mmOracleGate.test.ts +0 -379
- package/tests/oracles/pythPegSnap.test.ts +0 -76
- package/tests/sdkParity/enumParity.test.ts +0 -84
- package/tests/sdkParity/marginCategoryFill.test.ts +0 -143
- package/tests/sdkParity/memcmpOffsets.test.ts +0 -139
- package/tests/spot/test.ts +0 -281
- package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
- package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
- package/tests/tx/priorityFeeCalculator.ts +0 -77
- package/tests/tx/priorityFeeStrategy.ts +0 -95
- package/tests/user/bankruptcy.ts +0 -165
- package/tests/user/feeAndWithdrawLimits.ts +0 -284
- package/tests/user/getMarginCalculation.ts +0 -586
- package/tests/user/helpers.ts +0 -184
- package/tests/user/liquidations.ts +0 -129
- package/tests/user/marginCalculations.test.ts +0 -321
- package/tests/user/test.ts +0 -833
- package/tsconfig.browser.json +0 -18
- package/tsconfig.json +0 -36
|
@@ -1,774 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AccountToPoll,
|
|
3
|
-
DataAndSlot,
|
|
4
|
-
DelistedMarketSetting,
|
|
5
|
-
VelocityClientAccountEvents,
|
|
6
|
-
VelocityClientAccountSubscriber,
|
|
7
|
-
NotSubscribedError,
|
|
8
|
-
OraclesToPoll,
|
|
9
|
-
} from './types';
|
|
10
|
-
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
11
|
-
import { EventEmitter } from 'events';
|
|
12
|
-
import {
|
|
13
|
-
PerpMarketAccount,
|
|
14
|
-
SpotMarketAccount,
|
|
15
|
-
StateAccount,
|
|
16
|
-
UserAccount,
|
|
17
|
-
OracleSource,
|
|
18
|
-
} from '../types';
|
|
19
|
-
import {
|
|
20
|
-
getVelocityStateAccountPublicKey,
|
|
21
|
-
getPerpMarketPublicKey,
|
|
22
|
-
getSpotMarketPublicKey,
|
|
23
|
-
} from '../addresses/pda';
|
|
24
|
-
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
25
|
-
import { findDelistedPerpMarketsAndOracles } from './utils';
|
|
26
|
-
import { PublicKey } from '@solana/web3.js';
|
|
27
|
-
import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
28
|
-
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
29
|
-
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
30
|
-
import { findAllMarketAndOracles, VelocityProgram } from '../config';
|
|
31
|
-
import { getOracleId } from '../oracles/oracleId';
|
|
32
|
-
|
|
33
|
-
const ORACLE_DEFAULT_ID = getOracleId(
|
|
34
|
-
PublicKey.default,
|
|
35
|
-
OracleSource.QUOTE_ASSET
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* `VelocityClientAccountSubscriber` that batches the `State`, every tracked `PerpMarket`/
|
|
40
|
-
* `SpotMarket`, and every tracked oracle behind a single `BulkAccountLoader` instead of one
|
|
41
|
-
* WebSocket subscription per account. Cheaper on connection count at the cost of update latency
|
|
42
|
-
* bounded by the loader's poll interval. `subscribe()` retries the initial load up to 5 times
|
|
43
|
-
* before giving up (returning `false`) if the `State` account never appears — `didSubscriptionSucceed`
|
|
44
|
-
* checks only for `state`, since market/oracle data can be added incrementally afterward via
|
|
45
|
-
* `addPerpMarket`/`addSpotMarket`/`addOracle`.
|
|
46
|
-
*/
|
|
47
|
-
export class PollingVelocityClientAccountSubscriber
|
|
48
|
-
implements VelocityClientAccountSubscriber
|
|
49
|
-
{
|
|
50
|
-
isSubscribed: boolean;
|
|
51
|
-
program: VelocityProgram;
|
|
52
|
-
perpMarketIndexes: number[];
|
|
53
|
-
spotMarketIndexes: number[];
|
|
54
|
-
oracleInfos: OracleInfo[];
|
|
55
|
-
oracleClientCache = new OracleClientCache();
|
|
56
|
-
|
|
57
|
-
shouldFindAllMarketsAndOracles: boolean;
|
|
58
|
-
|
|
59
|
-
eventEmitter: StrictEventEmitter<EventEmitter, VelocityClientAccountEvents>;
|
|
60
|
-
|
|
61
|
-
accountLoader: BulkAccountLoader;
|
|
62
|
-
accountsToPoll = new Map<string, AccountToPoll>();
|
|
63
|
-
oraclesToPoll = new Map<string, OraclesToPoll>();
|
|
64
|
-
errorCallbackId?: string;
|
|
65
|
-
|
|
66
|
-
state?: DataAndSlot<StateAccount>;
|
|
67
|
-
perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
|
|
68
|
-
perpOracleMap = new Map<number, PublicKey>();
|
|
69
|
-
perpOracleStringMap = new Map<number, string>();
|
|
70
|
-
spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
|
|
71
|
-
spotOracleMap = new Map<number, PublicKey>();
|
|
72
|
-
spotOracleStringMap = new Map<number, string>();
|
|
73
|
-
oracles = new Map<string, DataAndSlot<OraclePriceData>>();
|
|
74
|
-
user?: DataAndSlot<UserAccount>;
|
|
75
|
-
delistedMarketSetting: DelistedMarketSetting;
|
|
76
|
-
|
|
77
|
-
private isSubscribing = false;
|
|
78
|
-
private subscriptionPromiseResolver: (val: boolean) => void = () => {};
|
|
79
|
-
private subscriptionPromise: Promise<boolean> = new Promise((res) => {
|
|
80
|
-
this.subscriptionPromiseResolver = res;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @param program Anchor program used to derive PDAs, decode accounts, and resolve oracle clients.
|
|
85
|
-
* @param accountLoader Shared `BulkAccountLoader` all state/market/oracle accounts are registered with.
|
|
86
|
-
* @param perpMarketIndexes Perp market indexes to track, if `shouldFindAllMarketsAndOracles` is false.
|
|
87
|
-
* @param spotMarketIndexes Spot market indexes to track, if `shouldFindAllMarketsAndOracles` is false.
|
|
88
|
-
* @param oracleInfos Oracles to track up front, if `shouldFindAllMarketsAndOracles` is false.
|
|
89
|
-
* @param shouldFindAllMarketsAndOracles If true, `subscribe()` first discovers every market/oracle from on-chain state, ignoring the index/info args above.
|
|
90
|
-
* @param delistedMarketSetting Behavior applied to delisted perp markets/oracles after subscribing; see `DelistedMarketSetting`.
|
|
91
|
-
*/
|
|
92
|
-
public constructor(
|
|
93
|
-
program: VelocityProgram,
|
|
94
|
-
accountLoader: BulkAccountLoader,
|
|
95
|
-
perpMarketIndexes: number[],
|
|
96
|
-
spotMarketIndexes: number[],
|
|
97
|
-
oracleInfos: OracleInfo[],
|
|
98
|
-
shouldFindAllMarketsAndOracles: boolean,
|
|
99
|
-
delistedMarketSetting: DelistedMarketSetting
|
|
100
|
-
) {
|
|
101
|
-
this.isSubscribed = false;
|
|
102
|
-
this.program = program;
|
|
103
|
-
this.eventEmitter = new EventEmitter();
|
|
104
|
-
this.accountLoader = accountLoader;
|
|
105
|
-
this.perpMarketIndexes = perpMarketIndexes;
|
|
106
|
-
this.spotMarketIndexes = spotMarketIndexes;
|
|
107
|
-
this.oracleInfos = oracleInfos;
|
|
108
|
-
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
109
|
-
this.delistedMarketSetting = delistedMarketSetting;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Registers state/market/oracle accounts with the `BulkAccountLoader` and retries the initial
|
|
114
|
-
* load up to 5 times until the `State` account has appeared. Idempotent: a no-op if already
|
|
115
|
-
* subscribed, and concurrent calls while a subscribe is in flight share the same result via
|
|
116
|
-
* `subscriptionPromise` rather than issuing duplicate loads.
|
|
117
|
-
* @returns `true` if `State` account data loaded within the retry budget, `false` otherwise.
|
|
118
|
-
*/
|
|
119
|
-
public async subscribe(): Promise<boolean> {
|
|
120
|
-
if (this.isSubscribed) {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (this.isSubscribing) {
|
|
125
|
-
return await this.subscriptionPromise;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this.isSubscribing = true;
|
|
129
|
-
|
|
130
|
-
this.subscriptionPromise = new Promise((res) => {
|
|
131
|
-
this.subscriptionPromiseResolver = res;
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
if (this.shouldFindAllMarketsAndOracles) {
|
|
135
|
-
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } =
|
|
136
|
-
await findAllMarketAndOracles(this.program);
|
|
137
|
-
this.perpMarketIndexes = perpMarketIndexes;
|
|
138
|
-
this.spotMarketIndexes = spotMarketIndexes;
|
|
139
|
-
this.oracleInfos = oracleInfos;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
await this.updateAccountsToPoll();
|
|
143
|
-
this.updateOraclesToPoll();
|
|
144
|
-
await this.addToAccountLoader();
|
|
145
|
-
|
|
146
|
-
let subscriptionSucceeded = false;
|
|
147
|
-
let retries = 0;
|
|
148
|
-
while (!subscriptionSucceeded && retries < 5) {
|
|
149
|
-
await this.fetch();
|
|
150
|
-
subscriptionSucceeded = this.didSubscriptionSucceed();
|
|
151
|
-
retries++;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (subscriptionSucceeded) {
|
|
155
|
-
this.eventEmitter.emit('update');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
this.handleDelistedMarkets();
|
|
159
|
-
|
|
160
|
-
await Promise.all([this.setPerpOracleMap(), this.setSpotOracleMap()]);
|
|
161
|
-
|
|
162
|
-
this.isSubscribing = false;
|
|
163
|
-
this.isSubscribed = subscriptionSucceeded;
|
|
164
|
-
this.subscriptionPromiseResolver(subscriptionSucceeded);
|
|
165
|
-
|
|
166
|
-
return subscriptionSucceeded;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async updateAccountsToPoll(): Promise<void> {
|
|
170
|
-
if (this.accountsToPoll.size > 0) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const statePublicKey = await getVelocityStateAccountPublicKey(
|
|
175
|
-
this.program.programId
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
this.accountsToPoll.set(statePublicKey.toString(), {
|
|
179
|
-
key: 'state',
|
|
180
|
-
publicKey: statePublicKey,
|
|
181
|
-
eventType: 'stateAccountUpdate',
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
await Promise.all([
|
|
185
|
-
this.updatePerpMarketAccountsToPoll(),
|
|
186
|
-
this.updateSpotMarketAccountsToPoll(),
|
|
187
|
-
]);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
async updatePerpMarketAccountsToPoll(): Promise<boolean> {
|
|
191
|
-
await Promise.all(
|
|
192
|
-
this.perpMarketIndexes.map((marketIndex) => {
|
|
193
|
-
return this.addPerpMarketAccountToPoll(marketIndex);
|
|
194
|
-
})
|
|
195
|
-
);
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async addPerpMarketAccountToPoll(marketIndex: number): Promise<boolean> {
|
|
200
|
-
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
201
|
-
this.program.programId,
|
|
202
|
-
marketIndex
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
this.accountsToPoll.set(perpMarketPublicKey.toString(), {
|
|
206
|
-
key: 'perpMarket',
|
|
207
|
-
publicKey: perpMarketPublicKey,
|
|
208
|
-
eventType: 'perpMarketAccountUpdate',
|
|
209
|
-
mapKey: marketIndex,
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async updateSpotMarketAccountsToPoll(): Promise<boolean> {
|
|
216
|
-
await Promise.all(
|
|
217
|
-
this.spotMarketIndexes.map(async (marketIndex) => {
|
|
218
|
-
await this.addSpotMarketAccountToPoll(marketIndex);
|
|
219
|
-
})
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
return true;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
async addSpotMarketAccountToPoll(marketIndex: number): Promise<boolean> {
|
|
226
|
-
const marketPublicKey = await getSpotMarketPublicKey(
|
|
227
|
-
this.program.programId,
|
|
228
|
-
marketIndex
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
this.accountsToPoll.set(marketPublicKey.toString(), {
|
|
232
|
-
key: 'spotMarket',
|
|
233
|
-
publicKey: marketPublicKey,
|
|
234
|
-
eventType: 'spotMarketAccountUpdate',
|
|
235
|
-
mapKey: marketIndex,
|
|
236
|
-
});
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
updateOraclesToPoll(): boolean {
|
|
241
|
-
for (const oracleInfo of this.oracleInfos) {
|
|
242
|
-
if (!oracleInfo.publicKey.equals(PublicKey.default)) {
|
|
243
|
-
this.addOracleToPoll(oracleInfo);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
addOracleToPoll(oracleInfo: OracleInfo): boolean {
|
|
251
|
-
this.oraclesToPoll.set(
|
|
252
|
-
getOracleId(oracleInfo.publicKey, oracleInfo.source),
|
|
253
|
-
{
|
|
254
|
-
publicKey: oracleInfo.publicKey,
|
|
255
|
-
source: oracleInfo.source,
|
|
256
|
-
}
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
async addToAccountLoader(): Promise<void> {
|
|
262
|
-
const accountPromises = [];
|
|
263
|
-
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
264
|
-
accountPromises.push(this.addAccountToAccountLoader(accountToPoll));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const oraclePromises = [];
|
|
268
|
-
for (const [_, oracleToPoll] of this.oraclesToPoll) {
|
|
269
|
-
oraclePromises.push(this.addOracleToAccountLoader(oracleToPoll));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
await Promise.all([...accountPromises, ...oraclePromises]);
|
|
273
|
-
|
|
274
|
-
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
275
|
-
this.eventEmitter.emit('error', error);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Routes a freshly-decoded account into the correct container based on
|
|
281
|
-
* its poll key. Replaces dynamic `this[key]` indexing with explicit,
|
|
282
|
-
* type-checked dispatch.
|
|
283
|
-
*/
|
|
284
|
-
private storeDecodedAccount(
|
|
285
|
-
accountToPoll: AccountToPoll,
|
|
286
|
-
account: any,
|
|
287
|
-
slot: number
|
|
288
|
-
): void {
|
|
289
|
-
const dataAndSlot = { data: account, slot };
|
|
290
|
-
switch (accountToPoll.key) {
|
|
291
|
-
case 'perpMarket':
|
|
292
|
-
if (accountToPoll.mapKey !== undefined) {
|
|
293
|
-
this.perpMarket.set(accountToPoll.mapKey, dataAndSlot);
|
|
294
|
-
}
|
|
295
|
-
break;
|
|
296
|
-
case 'spotMarket':
|
|
297
|
-
if (accountToPoll.mapKey !== undefined) {
|
|
298
|
-
this.spotMarket.set(accountToPoll.mapKey, dataAndSlot);
|
|
299
|
-
}
|
|
300
|
-
break;
|
|
301
|
-
case 'state':
|
|
302
|
-
this.state = dataAndSlot;
|
|
303
|
-
break;
|
|
304
|
-
default: {
|
|
305
|
-
const _exhaustive: never = accountToPoll.key;
|
|
306
|
-
throw new Error(`Unhandled account poll key: ${String(_exhaustive)}`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async addAccountToAccountLoader(accountToPoll: AccountToPoll): Promise<void> {
|
|
312
|
-
accountToPoll.callbackId = await this.accountLoader.addAccount(
|
|
313
|
-
accountToPoll.publicKey,
|
|
314
|
-
(buffer: Buffer, slot: number) => {
|
|
315
|
-
if (!buffer) return;
|
|
316
|
-
|
|
317
|
-
const account = this.program.coder.accounts.decodeUnchecked(
|
|
318
|
-
accountToPoll.key,
|
|
319
|
-
buffer
|
|
320
|
-
);
|
|
321
|
-
this.storeDecodedAccount(accountToPoll, account, slot);
|
|
322
|
-
|
|
323
|
-
// @ts-ignore
|
|
324
|
-
this.eventEmitter.emit(accountToPoll.eventType, account);
|
|
325
|
-
this.eventEmitter.emit('update');
|
|
326
|
-
|
|
327
|
-
if (!this.isSubscribed) {
|
|
328
|
-
this.isSubscribed = this.didSubscriptionSucceed();
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async addOracleToAccountLoader(oracleToPoll: OraclesToPoll): Promise<void> {
|
|
335
|
-
const oracleClient = this.oracleClientCache.get(
|
|
336
|
-
oracleToPoll.source,
|
|
337
|
-
this.program.provider.connection,
|
|
338
|
-
this.program
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
const oracleId = getOracleId(oracleToPoll.publicKey, oracleToPoll.source);
|
|
342
|
-
|
|
343
|
-
oracleToPoll.callbackId = await this.accountLoader.addAccount(
|
|
344
|
-
oracleToPoll.publicKey,
|
|
345
|
-
(buffer: Buffer, slot: number) => {
|
|
346
|
-
if (!buffer) return;
|
|
347
|
-
if (!oracleClient) return;
|
|
348
|
-
|
|
349
|
-
const oraclePriceData =
|
|
350
|
-
oracleClient.getOraclePriceDataFromBuffer(buffer);
|
|
351
|
-
const dataAndSlot = {
|
|
352
|
-
data: oraclePriceData,
|
|
353
|
-
slot,
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
this.oracles.set(oracleId, dataAndSlot);
|
|
357
|
-
|
|
358
|
-
this.eventEmitter.emit(
|
|
359
|
-
'oraclePriceUpdate',
|
|
360
|
-
oracleToPoll.publicKey,
|
|
361
|
-
oracleToPoll.source,
|
|
362
|
-
oraclePriceData
|
|
363
|
-
);
|
|
364
|
-
this.eventEmitter.emit('update');
|
|
365
|
-
}
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/** Forces the shared `BulkAccountLoader` to load, then re-decodes every tracked state/market/oracle account from the loader's cached buffers into this subscriber's maps. */
|
|
370
|
-
public async fetch(): Promise<void> {
|
|
371
|
-
await this.accountLoader.load();
|
|
372
|
-
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
373
|
-
const bufferAndSlot = this.accountLoader.getBufferAndSlot(
|
|
374
|
-
accountToPoll.publicKey
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
if (!bufferAndSlot) {
|
|
378
|
-
continue;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const { buffer, slot } = bufferAndSlot;
|
|
382
|
-
|
|
383
|
-
if (buffer) {
|
|
384
|
-
const account = this.program.coder.accounts.decodeUnchecked(
|
|
385
|
-
accountToPoll.key,
|
|
386
|
-
buffer
|
|
387
|
-
);
|
|
388
|
-
this.storeDecodedAccount(accountToPoll, account, slot);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
for (const [_, oracleToPoll] of this.oraclesToPoll) {
|
|
393
|
-
const bufferAndSlot = this.accountLoader.getBufferAndSlot(
|
|
394
|
-
oracleToPoll.publicKey
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
if (!bufferAndSlot) {
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const { buffer, slot } = bufferAndSlot;
|
|
402
|
-
|
|
403
|
-
if (buffer) {
|
|
404
|
-
const oracleClient = this.oracleClientCache.get(
|
|
405
|
-
oracleToPoll.source,
|
|
406
|
-
this.program.provider.connection,
|
|
407
|
-
this.program
|
|
408
|
-
);
|
|
409
|
-
if (!oracleClient) {
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
const oraclePriceData =
|
|
413
|
-
oracleClient.getOraclePriceDataFromBuffer(buffer);
|
|
414
|
-
this.oracles.set(
|
|
415
|
-
getOracleId(oracleToPoll.publicKey, oracleToPoll.source),
|
|
416
|
-
{
|
|
417
|
-
data: oraclePriceData,
|
|
418
|
-
slot,
|
|
419
|
-
}
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/** True once the `State` account has loaded, independent of `isSubscribed`. Market/oracle data is not required. */
|
|
426
|
-
didSubscriptionSucceed(): boolean {
|
|
427
|
-
if (this.state) return true;
|
|
428
|
-
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/** Removes every tracked state/market/oracle account and the error callback from the `BulkAccountLoader`, then clears internal maps. */
|
|
433
|
-
public async unsubscribe(): Promise<void> {
|
|
434
|
-
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
435
|
-
this.accountLoader.removeAccount(
|
|
436
|
-
accountToPoll.publicKey,
|
|
437
|
-
accountToPoll.callbackId
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
for (const [_, oracleToPoll] of this.oraclesToPoll) {
|
|
442
|
-
this.accountLoader.removeAccount(
|
|
443
|
-
oracleToPoll.publicKey,
|
|
444
|
-
oracleToPoll.callbackId
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
449
|
-
this.errorCallbackId = undefined;
|
|
450
|
-
|
|
451
|
-
this.accountsToPoll.clear();
|
|
452
|
-
this.oraclesToPoll.clear();
|
|
453
|
-
this.isSubscribed = false;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Adds a spot market (and its oracle, via `setSpotOracleMap`) to be tracked, registering it
|
|
458
|
-
* with the `BulkAccountLoader`. Idempotent: returns `true` immediately if already tracked.
|
|
459
|
-
* @param marketIndex Spot market index to start tracking.
|
|
460
|
-
*/
|
|
461
|
-
async addSpotMarket(marketIndex: number): Promise<boolean> {
|
|
462
|
-
const marketPublicKey = await getSpotMarketPublicKey(
|
|
463
|
-
this.program.programId,
|
|
464
|
-
marketIndex
|
|
465
|
-
);
|
|
466
|
-
|
|
467
|
-
if (this.accountsToPoll.has(marketPublicKey.toString())) {
|
|
468
|
-
return true;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
await this.addSpotMarketAccountToPoll(marketIndex);
|
|
472
|
-
|
|
473
|
-
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
474
|
-
if (!accountToPoll) {
|
|
475
|
-
return false;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
await this.addAccountToAccountLoader(accountToPoll);
|
|
479
|
-
await this.setSpotOracleMap();
|
|
480
|
-
return true;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Adds a perp market (and its oracle, via `setPerpOracleMap`) to be tracked, registering it
|
|
485
|
-
* with the `BulkAccountLoader`. Idempotent: returns `true` immediately if already tracked.
|
|
486
|
-
* @param marketIndex Perp market index to start tracking.
|
|
487
|
-
*/
|
|
488
|
-
async addPerpMarket(marketIndex: number): Promise<boolean> {
|
|
489
|
-
const marketPublicKey = await getPerpMarketPublicKey(
|
|
490
|
-
this.program.programId,
|
|
491
|
-
marketIndex
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
if (this.accountsToPoll.has(marketPublicKey.toString())) {
|
|
495
|
-
return true;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
await this.addPerpMarketAccountToPoll(marketIndex);
|
|
499
|
-
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
500
|
-
if (!accountToPoll) {
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
await this.addAccountToAccountLoader(accountToPoll);
|
|
504
|
-
await this.setPerpOracleMap();
|
|
505
|
-
return true;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Adds an oracle to be tracked, registering it with the `BulkAccountLoader` and waiting
|
|
510
|
-
* (polling up to 3 times at `accountLoader.pollingFrequency` intervals) for it to appear in
|
|
511
|
-
* the loader's buffer map before resolving. A no-op that resolves `true` immediately for the
|
|
512
|
-
* `PublicKey.default` sentinel (quote-asset "no oracle") or an oracle already tracked.
|
|
513
|
-
* @param oracleInfo Oracle pubkey and source to start tracking.
|
|
514
|
-
*/
|
|
515
|
-
async addOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
516
|
-
const oracleId = getOracleId(oracleInfo.publicKey, oracleInfo.source);
|
|
517
|
-
if (
|
|
518
|
-
oracleInfo.publicKey.equals(PublicKey.default) ||
|
|
519
|
-
this.oracles.has(oracleId)
|
|
520
|
-
) {
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// this func can be called multiple times before the first pauseForOracleToBeAdded finishes
|
|
525
|
-
// avoid adding to oraclesToPoll multiple time
|
|
526
|
-
if (!this.oraclesToPoll.has(oracleId)) {
|
|
527
|
-
this.addOracleToPoll(oracleInfo);
|
|
528
|
-
const oracleToPoll = this.oraclesToPoll.get(oracleId);
|
|
529
|
-
if (oracleToPoll) {
|
|
530
|
-
await this.addOracleToAccountLoader(oracleToPoll);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
await this.pauseForOracleToBeAdded(3, oracleInfo.publicKey.toBase58());
|
|
535
|
-
|
|
536
|
-
return true;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
private async pauseForOracleToBeAdded(
|
|
540
|
-
tries: number,
|
|
541
|
-
oracle: string
|
|
542
|
-
): Promise<void> {
|
|
543
|
-
let i = 0;
|
|
544
|
-
while (i < tries) {
|
|
545
|
-
await new Promise((r) =>
|
|
546
|
-
setTimeout(r, this.accountLoader.pollingFrequency)
|
|
547
|
-
);
|
|
548
|
-
if (this.accountLoader.bufferAndSlotMap.has(oracle)) {
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
i++;
|
|
552
|
-
}
|
|
553
|
-
console.log(`Pausing to find oracle ${oracle} failed`);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/** Rebuilds `perpOracleMap`/`perpOracleStringMap` from currently cached perp markets, calling `addOracle` for any oracle not yet tracked. */
|
|
557
|
-
async setPerpOracleMap() {
|
|
558
|
-
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
559
|
-
const oraclePromises = [];
|
|
560
|
-
for (const perpMarket of perpMarkets) {
|
|
561
|
-
const perpMarketAccount = perpMarket.data;
|
|
562
|
-
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
563
|
-
const oracle = perpMarketAccount.oracle;
|
|
564
|
-
const oracleId = getOracleId(oracle, perpMarketAccount.oracleSource);
|
|
565
|
-
if (!this.oracles.has(oracleId)) {
|
|
566
|
-
oraclePromises.push(
|
|
567
|
-
this.addOracle({
|
|
568
|
-
publicKey: oracle,
|
|
569
|
-
source: perpMarketAccount.oracleSource,
|
|
570
|
-
})
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
574
|
-
this.perpOracleStringMap.set(perpMarketIndex, oracleId);
|
|
575
|
-
}
|
|
576
|
-
await Promise.all(oraclePromises);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/** Rebuilds `spotOracleMap`/`spotOracleStringMap` from currently cached spot markets, calling `addOracle` for any oracle not yet tracked. */
|
|
580
|
-
async setSpotOracleMap() {
|
|
581
|
-
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
582
|
-
const oraclePromises = [];
|
|
583
|
-
for (const spotMarket of spotMarkets) {
|
|
584
|
-
const spotMarketAccount = spotMarket.data;
|
|
585
|
-
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
586
|
-
const oracle = spotMarketAccount.oracle;
|
|
587
|
-
const oracleId = getOracleId(oracle, spotMarketAccount.oracleSource);
|
|
588
|
-
if (!this.oracles.has(oracleId)) {
|
|
589
|
-
oraclePromises.push(
|
|
590
|
-
this.addOracle({
|
|
591
|
-
publicKey: oracle,
|
|
592
|
-
source: spotMarketAccount.oracleSource,
|
|
593
|
-
})
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
597
|
-
this.spotOracleStringMap.set(spotMarketIndex, oracleId);
|
|
598
|
-
}
|
|
599
|
-
await Promise.all(oraclePromises);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Applies `delistedMarketSetting` to any perp market currently `status: delisted` (and its
|
|
604
|
-
* oracle, if not shared with a live spot market): removes the `BulkAccountLoader` registration,
|
|
605
|
-
* and additionally drops the market/oracle from internal maps if the setting is `Discard`. A
|
|
606
|
-
* no-op if the setting is `Subscribe`. Throws if internal bookkeeping is inconsistent (e.g. a
|
|
607
|
-
* delisted market missing from `accountsToPoll`), which would indicate a bug rather than an
|
|
608
|
-
* expected runtime condition.
|
|
609
|
-
*/
|
|
610
|
-
handleDelistedMarkets(): void {
|
|
611
|
-
if (this.delistedMarketSetting === DelistedMarketSetting.Subscribe) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
const { perpMarketIndexes, oracles } = findDelistedPerpMarketsAndOracles(
|
|
616
|
-
this.getMarketAccountsAndSlots(),
|
|
617
|
-
this.getSpotMarketAccountsAndSlots()
|
|
618
|
-
);
|
|
619
|
-
|
|
620
|
-
for (const perpMarketIndex of perpMarketIndexes) {
|
|
621
|
-
const perpMarketData = this.perpMarket.get(perpMarketIndex);
|
|
622
|
-
if (!perpMarketData) {
|
|
623
|
-
throw new Error(
|
|
624
|
-
`PollingVelocityClientAccountSubscriber: delisted perp market ${perpMarketIndex} not found in perpMarket map`
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
const perpMarketPubkey = perpMarketData.data.pubkey;
|
|
628
|
-
const accountToPoll = this.accountsToPoll.get(
|
|
629
|
-
perpMarketPubkey.toBase58()
|
|
630
|
-
);
|
|
631
|
-
if (!accountToPoll) {
|
|
632
|
-
throw new Error(
|
|
633
|
-
`PollingVelocityClientAccountSubscriber: delisted perp market ${perpMarketIndex} not found in accountsToPoll map`
|
|
634
|
-
);
|
|
635
|
-
}
|
|
636
|
-
const callbackId = accountToPoll.callbackId;
|
|
637
|
-
this.accountLoader.removeAccount(perpMarketPubkey, callbackId);
|
|
638
|
-
if (this.delistedMarketSetting === DelistedMarketSetting.Discard) {
|
|
639
|
-
this.perpMarket.delete(perpMarketIndex);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
for (const oracle of oracles) {
|
|
644
|
-
const oracleId = getOracleId(oracle.publicKey, oracle.source);
|
|
645
|
-
const oracleToPoll = this.oraclesToPoll.get(oracleId);
|
|
646
|
-
if (!oracleToPoll) {
|
|
647
|
-
throw new Error(
|
|
648
|
-
`PollingVelocityClientAccountSubscriber: delisted oracle ${oracleId} not found in oraclesToPoll map`
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
const callbackId = oracleToPoll.callbackId;
|
|
652
|
-
this.accountLoader.removeAccount(oracle.publicKey, callbackId);
|
|
653
|
-
if (this.delistedMarketSetting === DelistedMarketSetting.Discard) {
|
|
654
|
-
this.oracles.delete(oracleId);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
/** Throws `NotSubscribedError` if `subscribe()` has not been called. */
|
|
660
|
-
assertIsSubscribed(): void {
|
|
661
|
-
if (!this.isSubscribed) {
|
|
662
|
-
throw new NotSubscribedError(
|
|
663
|
-
'You must call `subscribe` before using this function'
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
/** Throws `NotSubscribedError` if not subscribed. */
|
|
669
|
-
public getStateAccountAndSlot(): DataAndSlot<StateAccount> {
|
|
670
|
-
this.assertIsSubscribed();
|
|
671
|
-
return this.state!;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
/** Returns the cached perp market, or undefined if `marketIndex` isn't tracked (or hasn't loaded yet). Does not throw `NotSubscribedError`. */
|
|
675
|
-
public getMarketAccountAndSlot(
|
|
676
|
-
marketIndex: number
|
|
677
|
-
): DataAndSlot<PerpMarketAccount> | undefined {
|
|
678
|
-
return this.perpMarket.get(marketIndex);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/** Returns every currently cached perp market. Does not throw `NotSubscribedError`. */
|
|
682
|
-
public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
|
|
683
|
-
return Array.from(this.perpMarket.values());
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/** Returns the cached spot market, or undefined if `marketIndex` isn't tracked (or hasn't loaded yet). Does not throw `NotSubscribedError`. */
|
|
687
|
-
public getSpotMarketAccountAndSlot(
|
|
688
|
-
marketIndex: number
|
|
689
|
-
): DataAndSlot<SpotMarketAccount> | undefined {
|
|
690
|
-
return this.spotMarket.get(marketIndex);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/** Returns every currently cached spot market. Does not throw `NotSubscribedError`. */
|
|
694
|
-
public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
|
|
695
|
-
return Array.from(this.spotMarket.values());
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* Looks up cached oracle price data by oracle id (see `getOracleId`). Special-cases the
|
|
700
|
-
* quote-asset default oracle id, returning the constant `QUOTE_ORACLE_PRICE_DATA` at slot 0
|
|
701
|
-
* rather than a map lookup, since that oracle is never actually subscribed to.
|
|
702
|
-
* @param oracleId Oracle id string from `getOracleId(publicKey, source)`.
|
|
703
|
-
* @returns Cached price data/slot, or undefined if not tracked. Throws `NotSubscribedError` if not subscribed.
|
|
704
|
-
*/
|
|
705
|
-
public getOraclePriceDataAndSlot(
|
|
706
|
-
oracleId: string
|
|
707
|
-
): DataAndSlot<OraclePriceData> | undefined {
|
|
708
|
-
this.assertIsSubscribed();
|
|
709
|
-
if (oracleId === ORACLE_DEFAULT_ID) {
|
|
710
|
-
return {
|
|
711
|
-
data: QUOTE_ORACLE_PRICE_DATA,
|
|
712
|
-
slot: 0,
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
return this.oracles.get(oracleId);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
/**
|
|
720
|
-
* Convenience lookup: resolves the oracle price data currently mapped to a perp market's
|
|
721
|
-
* oracle. If the cached market's oracle pubkey has drifted from `perpOracleMap` (e.g. an admin
|
|
722
|
-
* changed it on-chain), triggers a background `setPerpOracleMap()` refresh and still returns
|
|
723
|
-
* the (possibly stale) mapping for this call.
|
|
724
|
-
* @param marketIndex Perp market index whose oracle price to look up.
|
|
725
|
-
*/
|
|
726
|
-
public getOraclePriceDataAndSlotForPerpMarket(
|
|
727
|
-
marketIndex: number
|
|
728
|
-
): DataAndSlot<OraclePriceData> | undefined {
|
|
729
|
-
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
730
|
-
const oracle = this.perpOracleMap.get(marketIndex);
|
|
731
|
-
const oracleId = this.perpOracleStringMap.get(marketIndex);
|
|
732
|
-
|
|
733
|
-
if (!perpMarketAccount || !oracle || !oracleId) {
|
|
734
|
-
return undefined;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
if (!perpMarketAccount.data.oracle.equals(oracle)) {
|
|
738
|
-
// If the oracle has changed, we need to update the oracle map in background
|
|
739
|
-
this.setPerpOracleMap();
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
return this.getOraclePriceDataAndSlot(oracleId);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Convenience lookup: resolves the oracle price data currently mapped to a spot market's
|
|
747
|
-
* oracle. If the cached market's oracle pubkey has drifted from `spotOracleMap`, triggers a
|
|
748
|
-
* background `setSpotOracleMap()` refresh and still returns the (possibly stale) mapping for
|
|
749
|
-
* this call.
|
|
750
|
-
* @param marketIndex Spot market index whose oracle price to look up.
|
|
751
|
-
*/
|
|
752
|
-
public getOraclePriceDataAndSlotForSpotMarket(
|
|
753
|
-
marketIndex: number
|
|
754
|
-
): DataAndSlot<OraclePriceData> | undefined {
|
|
755
|
-
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
756
|
-
const oracle = this.spotOracleMap.get(marketIndex);
|
|
757
|
-
const oracleId = this.spotOracleStringMap.get(marketIndex);
|
|
758
|
-
if (!spotMarketAccount || !oracle || !oracleId) {
|
|
759
|
-
return undefined;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
763
|
-
// If the oracle has changed, we need to update the oracle map in background
|
|
764
|
-
this.setSpotOracleMap();
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
return this.getOraclePriceDataAndSlot(oracleId);
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/** Retunes the shared `BulkAccountLoader`'s poll interval (ms) for every account it batches (affects other subscribers sharing the same loader too). */
|
|
771
|
-
public updateAccountLoaderPollingFrequency(pollingFrequency: number): void {
|
|
772
|
-
this.accountLoader.updatePollingFrequency(pollingFrequency);
|
|
773
|
-
}
|
|
774
|
-
}
|