@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,536 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DataAndSlot,
|
|
3
|
-
AccountSubscriber,
|
|
4
|
-
ResubOpts,
|
|
5
|
-
BufferAndSlot,
|
|
6
|
-
} from './types';
|
|
7
|
-
import { AnchorProvider } from '../isomorphic/anchor';
|
|
8
|
-
import { VelocityProgram } from '../config';
|
|
9
|
-
import {
|
|
10
|
-
AccountInfoBase,
|
|
11
|
-
AccountInfoWithBase64EncodedData,
|
|
12
|
-
AccountInfoWithBase58EncodedData,
|
|
13
|
-
createSolanaClient,
|
|
14
|
-
isAddress,
|
|
15
|
-
Rpc,
|
|
16
|
-
RpcSubscriptions,
|
|
17
|
-
SolanaRpcSubscriptionsApi,
|
|
18
|
-
Address,
|
|
19
|
-
Commitment,
|
|
20
|
-
} from 'gill';
|
|
21
|
-
import { PublicKey } from '@solana/web3.js';
|
|
22
|
-
import bs58 from 'bs58';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* WebSocketAccountSubscriberV2
|
|
26
|
-
*
|
|
27
|
-
* High-level overview
|
|
28
|
-
* - WebSocket-first subscriber for a single Solana account with optional
|
|
29
|
-
* polling safeguards when the WS feed goes quiet.
|
|
30
|
-
* - Emits decoded updates via `onChange` and maintains the latest
|
|
31
|
-
* `{buffer, slot}` and decoded `{data, slot}` internally.
|
|
32
|
-
*
|
|
33
|
-
* Why polling if this is a WebSocket subscriber?
|
|
34
|
-
* - Under real-world conditions, WS notifications can stall or get dropped.
|
|
35
|
-
* - When `resubOpts.resubTimeoutMs` elapses without WS data, you can either:
|
|
36
|
-
* - resubscribe to the WS stream (default), or
|
|
37
|
-
* - enable `resubOpts.usePollingInsteadOfResub` to start polling this single
|
|
38
|
-
* account via RPC to check for missed changes.
|
|
39
|
-
* - Polling compares the fetched buffer to the last known buffer. If different
|
|
40
|
-
* at an equal-or-later slot, it indicates a missed update and we resubscribe
|
|
41
|
-
* to WS to restore a clean stream.
|
|
42
|
-
*
|
|
43
|
-
* Initial fetch (on subscribe)
|
|
44
|
-
* - On `subscribe()`, we do a one-time RPC `fetch()` to seed internal state and
|
|
45
|
-
* emit the latest account state, ensuring consumers start from ground truth
|
|
46
|
-
* even before WS events arrive.
|
|
47
|
-
*
|
|
48
|
-
* Continuous polling (opt-in)
|
|
49
|
-
* - If `usePollingInsteadOfResub` is set, the inactivity timeout triggers a
|
|
50
|
-
* polling loop that periodically `fetch()`es the account and checks for
|
|
51
|
-
* changes. On change, polling stops and we resubscribe to WS.
|
|
52
|
-
* - If not set (default), the inactivity timeout immediately triggers a WS
|
|
53
|
-
* resubscription (no polling loop).
|
|
54
|
-
*
|
|
55
|
-
* Account focus
|
|
56
|
-
* - This class tracks exactly one account — the one passed to the constructor —
|
|
57
|
-
* which is by definition the account the consumer cares about. The extra
|
|
58
|
-
* logic is narrowly scoped to this account to minimize overhead.
|
|
59
|
-
*
|
|
60
|
-
* Tuning knobs
|
|
61
|
-
* - `resubOpts.resubTimeoutMs`: WS inactivity threshold before fallback.
|
|
62
|
-
* - `resubOpts.usePollingInsteadOfResub`: toggle polling vs immediate resub.
|
|
63
|
-
* - `resubOpts.pollingIntervalMs`: polling cadence (default 30s).
|
|
64
|
-
* - `resubOpts.logResubMessages`: verbose logs for diagnostics.
|
|
65
|
-
* - `commitment`: WS/RPC commitment used for reads and notifications.
|
|
66
|
-
* - `decodeBufferFn`: optional custom decode; defaults to Anchor coder.
|
|
67
|
-
*
|
|
68
|
-
* Implementation notes
|
|
69
|
-
* - Uses `gill` for both WS (`rpcSubscriptions`) and RPC (`rpc`) to match the
|
|
70
|
-
* program provider’s RPC endpoint. Handles base58/base64 encoded data.
|
|
71
|
-
*/
|
|
72
|
-
export class WebSocketAccountSubscriberV2<T> implements AccountSubscriber<T> {
|
|
73
|
-
dataAndSlot?: DataAndSlot<T>;
|
|
74
|
-
bufferAndSlot?: BufferAndSlot;
|
|
75
|
-
accountName: string;
|
|
76
|
-
logAccountName: string;
|
|
77
|
-
program: VelocityProgram;
|
|
78
|
-
accountPublicKey: PublicKey;
|
|
79
|
-
decodeBufferFn?: (buffer: Buffer) => T;
|
|
80
|
-
private _onChange?: (data: T) => void;
|
|
81
|
-
get onChange(): (data: T) => void {
|
|
82
|
-
if (!this._onChange) {
|
|
83
|
-
throw new Error('onChange callback function must be set');
|
|
84
|
-
}
|
|
85
|
-
return this._onChange;
|
|
86
|
-
}
|
|
87
|
-
set onChange(onChange: (data: T) => void) {
|
|
88
|
-
this._onChange = onChange;
|
|
89
|
-
}
|
|
90
|
-
listenerId?: number;
|
|
91
|
-
|
|
92
|
-
resubOpts: ResubOpts;
|
|
93
|
-
|
|
94
|
-
commitment?: Commitment;
|
|
95
|
-
isUnsubscribing = false;
|
|
96
|
-
|
|
97
|
-
timeoutId?: ReturnType<typeof setTimeout>;
|
|
98
|
-
pollingTimeoutId?: ReturnType<typeof setTimeout>;
|
|
99
|
-
|
|
100
|
-
receivingData: boolean;
|
|
101
|
-
|
|
102
|
-
// Gill client components
|
|
103
|
-
private rpc: ReturnType<typeof createSolanaClient>['rpc'];
|
|
104
|
-
private rpcSubscriptions: ReturnType<
|
|
105
|
-
typeof createSolanaClient
|
|
106
|
-
>['rpcSubscriptions'];
|
|
107
|
-
private abortController?: AbortController;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Create a single-account WebSocket subscriber with optional polling fallback.
|
|
111
|
-
*
|
|
112
|
-
* @param accountName Name of the Anchor account type (used for default decode).
|
|
113
|
-
* @param program Anchor `Program` used for decoding and provider access.
|
|
114
|
-
* @param accountPublicKey Public key of the account to track.
|
|
115
|
-
* @param decodeBuffer Optional custom decode function; if omitted, uses
|
|
116
|
-
* program coder to decode `accountName`.
|
|
117
|
-
* @param resubOpts Resubscription/polling options. See class docs.
|
|
118
|
-
* @param commitment Commitment for WS and RPC operations.
|
|
119
|
-
* @param rpcSubscriptions Optional override/injection for testing.
|
|
120
|
-
* @param rpc Optional override/injection for testing.
|
|
121
|
-
*/
|
|
122
|
-
public constructor(
|
|
123
|
-
accountName: string,
|
|
124
|
-
program: VelocityProgram,
|
|
125
|
-
accountPublicKey: PublicKey,
|
|
126
|
-
decodeBuffer?: (buffer: Buffer) => T,
|
|
127
|
-
resubOpts?: ResubOpts,
|
|
128
|
-
commitment?: Commitment,
|
|
129
|
-
rpcSubscriptions?: RpcSubscriptions<SolanaRpcSubscriptionsApi> & string,
|
|
130
|
-
rpc?: Rpc<any>
|
|
131
|
-
) {
|
|
132
|
-
this.accountName = accountName;
|
|
133
|
-
this.logAccountName = `${accountName}-${accountPublicKey.toBase58()}-ws-acct-subscriber-v2`;
|
|
134
|
-
this.program = program;
|
|
135
|
-
this.accountPublicKey = accountPublicKey;
|
|
136
|
-
this.decodeBufferFn = decodeBuffer;
|
|
137
|
-
this.resubOpts = resubOpts ?? {
|
|
138
|
-
resubTimeoutMs: 30000,
|
|
139
|
-
usePollingInsteadOfResub: true,
|
|
140
|
-
logResubMessages: false,
|
|
141
|
-
};
|
|
142
|
-
if (
|
|
143
|
-
this.resubOpts.resubTimeoutMs != null &&
|
|
144
|
-
this.resubOpts.resubTimeoutMs < 1000
|
|
145
|
-
) {
|
|
146
|
-
console.log(
|
|
147
|
-
`resubTimeoutMs should be at least 1000ms to avoid spamming resub ${this.logAccountName}`
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
this.receivingData = false;
|
|
151
|
-
if (
|
|
152
|
-
['recent', 'single', 'singleGossip', 'root', 'max'].includes(
|
|
153
|
-
(this.program.provider as AnchorProvider).opts.commitment ?? ''
|
|
154
|
-
)
|
|
155
|
-
) {
|
|
156
|
-
console.warn(
|
|
157
|
-
`using commitment ${
|
|
158
|
-
(this.program.provider as AnchorProvider).opts.commitment
|
|
159
|
-
} that is not supported by gill, this may cause issues`
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
this.commitment =
|
|
163
|
-
commitment ??
|
|
164
|
-
((this.program.provider as AnchorProvider).opts.commitment as Commitment);
|
|
165
|
-
|
|
166
|
-
// Initialize gill client using the same RPC URL as the program provider
|
|
167
|
-
|
|
168
|
-
this.rpc = rpc
|
|
169
|
-
? rpc
|
|
170
|
-
: (() => {
|
|
171
|
-
const rpcUrl = (this.program.provider as AnchorProvider).connection
|
|
172
|
-
.rpcEndpoint;
|
|
173
|
-
const { rpc } = createSolanaClient({
|
|
174
|
-
urlOrMoniker: rpcUrl,
|
|
175
|
-
});
|
|
176
|
-
return rpc;
|
|
177
|
-
})();
|
|
178
|
-
this.rpcSubscriptions = rpcSubscriptions
|
|
179
|
-
? rpcSubscriptions
|
|
180
|
-
: (() => {
|
|
181
|
-
const rpcUrl = (this.program.provider as AnchorProvider).connection
|
|
182
|
-
.rpcEndpoint;
|
|
183
|
-
const { rpcSubscriptions } = createSolanaClient({
|
|
184
|
-
urlOrMoniker: rpcUrl,
|
|
185
|
-
});
|
|
186
|
-
return rpcSubscriptions;
|
|
187
|
-
})();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private async handleNotificationLoop(
|
|
191
|
-
subscriptionPromise: Promise<AsyncIterable<any>>
|
|
192
|
-
) {
|
|
193
|
-
const subscription = await subscriptionPromise;
|
|
194
|
-
for await (const notification of subscription) {
|
|
195
|
-
// If we're currently polling and receive a WebSocket event, stop polling
|
|
196
|
-
if (this.pollingTimeoutId) {
|
|
197
|
-
if (this.resubOpts.logResubMessages) {
|
|
198
|
-
console.log(
|
|
199
|
-
`[${this.logAccountName}] Received WebSocket event while polling, stopping polling`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
this.stopPolling();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
this.receivingData = true;
|
|
206
|
-
clearTimeout(this.timeoutId);
|
|
207
|
-
this.handleRpcResponse(notification.context, notification.value);
|
|
208
|
-
this.setTimeout();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Seeds `dataAndSlot` with an initial `fetch()` (if not already set via `setData`), then opens
|
|
214
|
-
* the `gill` `accountNotifications` WebSocket subscription and, if `resubOpts.resubTimeoutMs`
|
|
215
|
-
* is set, arms the inactivity watchdog (`setTimeout`). Idempotent: a no-op if already
|
|
216
|
-
* subscribed or mid-unsubscribe.
|
|
217
|
-
* @param onChange Invoked with the newly decoded account data on each accepted update.
|
|
218
|
-
* @throws Error if `accountPublicKey` is not a valid address per `gill`'s `isAddress`.
|
|
219
|
-
*/
|
|
220
|
-
async subscribe(onChange: (data: T) => void): Promise<void> {
|
|
221
|
-
if (this.listenerId != null || this.isUnsubscribing) {
|
|
222
|
-
if (this.resubOpts.logResubMessages) {
|
|
223
|
-
console.log(
|
|
224
|
-
`[${this.logAccountName}] Subscribe returning early - listenerId=${this.listenerId}, isUnsubscribing=${this.isUnsubscribing}`
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
this.onChange = onChange;
|
|
231
|
-
if (!this.dataAndSlot) {
|
|
232
|
-
await this.fetch();
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Create abort controller for proper cleanup
|
|
236
|
-
const abortController = new AbortController();
|
|
237
|
-
this.abortController = abortController;
|
|
238
|
-
|
|
239
|
-
this.listenerId = Math.random(); // Unique ID for logging purposes
|
|
240
|
-
|
|
241
|
-
if (this.resubOpts.resubTimeoutMs) {
|
|
242
|
-
this.receivingData = true;
|
|
243
|
-
this.setTimeout();
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Subscribe to account changes using gill's rpcSubscriptions
|
|
247
|
-
const pubkey = this.accountPublicKey.toBase58();
|
|
248
|
-
if (isAddress(pubkey)) {
|
|
249
|
-
const subscriptionPromise = this.rpcSubscriptions
|
|
250
|
-
.accountNotifications(pubkey, {
|
|
251
|
-
commitment: this.commitment,
|
|
252
|
-
encoding: 'base64',
|
|
253
|
-
})
|
|
254
|
-
.subscribe({
|
|
255
|
-
abortSignal: abortController.signal,
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// Start notification loop with the subscription promise
|
|
259
|
-
this.handleNotificationLoop(subscriptionPromise);
|
|
260
|
-
} else {
|
|
261
|
-
throw new Error('Invalid account public key');
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Seeds or overwrites `dataAndSlot` directly, bypassing RPC. A no-op if the currently cached
|
|
267
|
-
* slot is already newer than `slot`.
|
|
268
|
-
* @param data Decoded account data to store.
|
|
269
|
-
* @param slot Slot the data was observed at; defaults to 0 (the seeded sentinel) if omitted.
|
|
270
|
-
*/
|
|
271
|
-
setData(data: T, slot?: number): void {
|
|
272
|
-
const newSlot = slot || 0;
|
|
273
|
-
if (this.dataAndSlot && this.dataAndSlot.slot > newSlot) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
this.dataAndSlot = {
|
|
278
|
-
data,
|
|
279
|
-
slot: newSlot,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Arms the inactivity watchdog: if no WS notification resets this timeout within
|
|
285
|
-
* `resubOpts.resubTimeoutMs`, either starts the polling fallback (`usePollingInsteadOfResub`)
|
|
286
|
-
* or tears down and recreates the WS subscription. Throws if `onChange` was never set (i.e.
|
|
287
|
-
* called outside `subscribe()`'s flow).
|
|
288
|
-
*/
|
|
289
|
-
protected setTimeout(): void {
|
|
290
|
-
if (!this._onChange) {
|
|
291
|
-
throw new Error('onChange callback function must be set');
|
|
292
|
-
}
|
|
293
|
-
this.timeoutId = setTimeout(async () => {
|
|
294
|
-
if (this.isUnsubscribing) {
|
|
295
|
-
// If we are in the process of unsubscribing, do not attempt to resubscribe
|
|
296
|
-
if (this.resubOpts.logResubMessages) {
|
|
297
|
-
console.log(
|
|
298
|
-
`[${this.logAccountName}] Timeout fired but isUnsubscribing=true, skipping resubscribe`
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (this.receivingData) {
|
|
305
|
-
if (this.resubOpts.usePollingInsteadOfResub) {
|
|
306
|
-
// Use polling instead of resubscribing
|
|
307
|
-
if (this.resubOpts.logResubMessages) {
|
|
308
|
-
console.log(
|
|
309
|
-
`[${this.logAccountName}] No ws data in ${this.resubOpts.resubTimeoutMs}ms, starting polling - listenerId=${this.listenerId}`
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
this.startPolling();
|
|
313
|
-
} else {
|
|
314
|
-
// Original resubscribe behavior
|
|
315
|
-
if (this.resubOpts.logResubMessages) {
|
|
316
|
-
console.log(
|
|
317
|
-
`No ws data from ${this.logAccountName} in ${this.resubOpts.resubTimeoutMs}ms, resubscribing - listenerId=${this.listenerId}, isUnsubscribing=${this.isUnsubscribing}`
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
await this.unsubscribe(true);
|
|
321
|
-
this.receivingData = false;
|
|
322
|
-
await this.subscribe(this.onChange);
|
|
323
|
-
if (this.resubOpts.logResubMessages) {
|
|
324
|
-
console.log(
|
|
325
|
-
`[${this.logAccountName}] Resubscribe completed - receivingData=${this.receivingData}, listenerId=${this.listenerId}, isUnsubscribing=${this.isUnsubscribing}`
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
if (this.resubOpts.logResubMessages) {
|
|
331
|
-
console.log(
|
|
332
|
-
`[${this.logAccountName}] Timeout fired but receivingData=false, skipping resubscribe`
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}, this.resubOpts.resubTimeoutMs);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Start the polling loop (single-account).
|
|
341
|
-
* - Periodically calls `fetch()` and compares buffers to detect changes.
|
|
342
|
-
* - On detected change, stops polling and resubscribes to WS.
|
|
343
|
-
*/
|
|
344
|
-
private startPolling(): void {
|
|
345
|
-
const pollingInterval = this.resubOpts.pollingIntervalMs || 30000; // Default to 30s
|
|
346
|
-
|
|
347
|
-
const poll = async () => {
|
|
348
|
-
if (this.isUnsubscribing) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
// Store current data and buffer before polling
|
|
354
|
-
const currentBuffer = this.bufferAndSlot?.buffer;
|
|
355
|
-
|
|
356
|
-
// Fetch latest account data
|
|
357
|
-
await this.fetch();
|
|
358
|
-
|
|
359
|
-
// Check if we got new data by comparing buffers
|
|
360
|
-
const newBuffer = this.bufferAndSlot?.buffer;
|
|
361
|
-
const hasNewData =
|
|
362
|
-
newBuffer && (!currentBuffer || !newBuffer.equals(currentBuffer));
|
|
363
|
-
|
|
364
|
-
if (hasNewData) {
|
|
365
|
-
// New data received, stop polling and resubscribe to websocket
|
|
366
|
-
if (this.resubOpts.logResubMessages) {
|
|
367
|
-
console.log(
|
|
368
|
-
`[${this.logAccountName}] Polling detected account data change, resubscribing to websocket`
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
await this.unsubscribe(true);
|
|
372
|
-
this.receivingData = false;
|
|
373
|
-
await this.subscribe(this.onChange);
|
|
374
|
-
} else {
|
|
375
|
-
// No new data, continue polling
|
|
376
|
-
if (this.resubOpts.logResubMessages) {
|
|
377
|
-
console.log(
|
|
378
|
-
`[${this.logAccountName}] Polling found no account changes, continuing to poll every ${pollingInterval}ms`
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
this.pollingTimeoutId = setTimeout(poll, pollingInterval);
|
|
382
|
-
}
|
|
383
|
-
} catch (error) {
|
|
384
|
-
if (this.resubOpts.logResubMessages) {
|
|
385
|
-
console.error(
|
|
386
|
-
`[${this.logAccountName}] Error during polling:`,
|
|
387
|
-
error
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
// On error, continue polling
|
|
391
|
-
this.pollingTimeoutId = setTimeout(poll, pollingInterval);
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
// Start polling immediately
|
|
396
|
-
poll();
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
private stopPolling(): void {
|
|
400
|
-
if (this.pollingTimeoutId) {
|
|
401
|
-
clearTimeout(this.pollingTimeoutId);
|
|
402
|
-
this.pollingTimeoutId = undefined;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Fetch the current account state via RPC and process it through the same
|
|
408
|
-
* decoding and update pathway as WS notifications.
|
|
409
|
-
*/
|
|
410
|
-
async fetch(): Promise<void> {
|
|
411
|
-
// Use gill's rpc for fetching account info
|
|
412
|
-
const accountAddress = this.accountPublicKey.toBase58() as Address;
|
|
413
|
-
const rpcResponse = await this.rpc
|
|
414
|
-
.getAccountInfo(accountAddress, {
|
|
415
|
-
commitment: this.commitment,
|
|
416
|
-
encoding: 'base64',
|
|
417
|
-
})
|
|
418
|
-
.send();
|
|
419
|
-
|
|
420
|
-
// Convert gill response to match the expected format
|
|
421
|
-
const context = {
|
|
422
|
-
slot: Number(rpcResponse.context.slot),
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
const accountInfo = rpcResponse.value;
|
|
426
|
-
|
|
427
|
-
this.handleRpcResponse(
|
|
428
|
-
{ slot: BigInt(context.slot) },
|
|
429
|
-
accountInfo ?? undefined
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Applies a raw `gill` RPC/WS response: decodes (base58 or base64) and stores it (updating
|
|
435
|
-
* `bufferAndSlot`/`dataAndSlot` and invoking `onChange`) only if the slot is not older than
|
|
436
|
-
* the cached one and the buffer's bytes actually changed (or this is the first observation).
|
|
437
|
-
*/
|
|
438
|
-
handleRpcResponse(
|
|
439
|
-
context: { slot: bigint },
|
|
440
|
-
accountInfo?: AccountInfoBase &
|
|
441
|
-
(AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)
|
|
442
|
-
): void {
|
|
443
|
-
const newSlot = context.slot;
|
|
444
|
-
let newBuffer: Buffer | undefined = undefined;
|
|
445
|
-
|
|
446
|
-
if (accountInfo) {
|
|
447
|
-
// Extract data from gill response
|
|
448
|
-
if (accountInfo.data) {
|
|
449
|
-
// Handle different data formats from gill
|
|
450
|
-
if (Array.isArray(accountInfo.data)) {
|
|
451
|
-
// If it's a tuple [data, encoding]
|
|
452
|
-
const [data, encoding] = accountInfo.data;
|
|
453
|
-
|
|
454
|
-
if (encoding === 'base58') {
|
|
455
|
-
// we know encoding will be base58
|
|
456
|
-
// Convert base58 to buffer using bs58
|
|
457
|
-
newBuffer = Buffer.from(bs58.decode(data));
|
|
458
|
-
} else {
|
|
459
|
-
newBuffer = Buffer.from(data, 'base64');
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if (!this.bufferAndSlot) {
|
|
466
|
-
this.bufferAndSlot = {
|
|
467
|
-
buffer: newBuffer,
|
|
468
|
-
slot: Number(newSlot),
|
|
469
|
-
};
|
|
470
|
-
if (newBuffer) {
|
|
471
|
-
const account = this.decodeBuffer(newBuffer);
|
|
472
|
-
this.dataAndSlot = {
|
|
473
|
-
data: account,
|
|
474
|
-
slot: Number(newSlot),
|
|
475
|
-
};
|
|
476
|
-
this.onChange(account);
|
|
477
|
-
}
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (Number(newSlot) < this.bufferAndSlot.slot) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const oldBuffer = this.bufferAndSlot.buffer;
|
|
486
|
-
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
|
|
487
|
-
this.bufferAndSlot = {
|
|
488
|
-
buffer: newBuffer,
|
|
489
|
-
slot: Number(newSlot),
|
|
490
|
-
};
|
|
491
|
-
const account = this.decodeBuffer(newBuffer);
|
|
492
|
-
this.dataAndSlot = {
|
|
493
|
-
data: account,
|
|
494
|
-
slot: Number(newSlot),
|
|
495
|
-
};
|
|
496
|
-
this.onChange(account);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/** Decodes a raw account buffer using the constructor-supplied `decodeBufferFn`, or the program's Anchor coder for `accountName` if none was supplied. */
|
|
501
|
-
decodeBuffer(buffer: Buffer): T {
|
|
502
|
-
if (this.decodeBufferFn) {
|
|
503
|
-
return this.decodeBufferFn(buffer);
|
|
504
|
-
} else {
|
|
505
|
-
return this.program.coder.accounts.decode(this.accountName, buffer);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Tears down the WebSocket subscription (via `abortController`) and cancels any pending resub
|
|
511
|
-
* timeout and in-progress polling.
|
|
512
|
-
* @param onResub Internal flag set to `true` when called as part of an automatic resubscribe cycle, which preserves `resubOpts.resubTimeoutMs` instead of clearing it. Callers should omit this.
|
|
513
|
-
*/
|
|
514
|
-
unsubscribe(onResub = false): Promise<void> {
|
|
515
|
-
if (!onResub && this.resubOpts) {
|
|
516
|
-
this.resubOpts.resubTimeoutMs = undefined;
|
|
517
|
-
}
|
|
518
|
-
this.isUnsubscribing = true;
|
|
519
|
-
clearTimeout(this.timeoutId);
|
|
520
|
-
this.timeoutId = undefined;
|
|
521
|
-
|
|
522
|
-
// Stop polling if active
|
|
523
|
-
this.stopPolling();
|
|
524
|
-
|
|
525
|
-
// Abort the WebSocket subscription
|
|
526
|
-
if (this.abortController) {
|
|
527
|
-
this.abortController.abort('unsubscribing');
|
|
528
|
-
this.abortController = undefined;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
this.listenerId = undefined;
|
|
532
|
-
this.isUnsubscribing = false;
|
|
533
|
-
|
|
534
|
-
return Promise.resolve();
|
|
535
|
-
}
|
|
536
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DataAndSlot,
|
|
3
|
-
AccountSubscriber,
|
|
4
|
-
NotSubscribedError,
|
|
5
|
-
InsuranceFundStakeAccountEvents,
|
|
6
|
-
InsuranceFundStakeAccountSubscriber,
|
|
7
|
-
} from './types';
|
|
8
|
-
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
9
|
-
import { EventEmitter } from 'events';
|
|
10
|
-
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
11
|
-
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
12
|
-
import { InsuranceFundStake } from '../types';
|
|
13
|
-
import { VelocityProgram } from '../config';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Default `InsuranceFundStakeAccountSubscriber` implementation: wraps a single
|
|
17
|
-
* `WebSocketAccountSubscriber` for the `InsuranceFundStake` account, mirroring
|
|
18
|
-
* `WebSocketUserAccountSubscriber`. `insuranceFundStakeDataAccountSubscriber` throws if accessed
|
|
19
|
-
* before `subscribe()` has run.
|
|
20
|
-
*/
|
|
21
|
-
export class WebSocketInsuranceFundStakeAccountSubscriber
|
|
22
|
-
implements InsuranceFundStakeAccountSubscriber
|
|
23
|
-
{
|
|
24
|
-
isSubscribed: boolean;
|
|
25
|
-
resubTimeoutMs?: number;
|
|
26
|
-
commitment?: Commitment;
|
|
27
|
-
program: VelocityProgram;
|
|
28
|
-
eventEmitter: StrictEventEmitter<
|
|
29
|
-
EventEmitter,
|
|
30
|
-
InsuranceFundStakeAccountEvents
|
|
31
|
-
>;
|
|
32
|
-
insuranceFundStakeAccountPublicKey: PublicKey;
|
|
33
|
-
|
|
34
|
-
private _insuranceFundStakeDataAccountSubscriber?: AccountSubscriber<InsuranceFundStake>;
|
|
35
|
-
get insuranceFundStakeDataAccountSubscriber(): AccountSubscriber<InsuranceFundStake> {
|
|
36
|
-
if (!this._insuranceFundStakeDataAccountSubscriber) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
'insuranceFundStakeDataAccountSubscriber accessed before subscribe()'
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
return this._insuranceFundStakeDataAccountSubscriber;
|
|
42
|
-
}
|
|
43
|
-
set insuranceFundStakeDataAccountSubscriber(
|
|
44
|
-
subscriber: AccountSubscriber<InsuranceFundStake>
|
|
45
|
-
) {
|
|
46
|
-
this._insuranceFundStakeDataAccountSubscriber = subscriber;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @param program Anchor program providing the connection and coder.
|
|
51
|
-
* @param insuranceFundStakeAccountPublicKey Address of the `InsuranceFundStake` account to track.
|
|
52
|
-
* @param resubTimeoutMs Resub watchdog timeout (ms) passed through as `ResubOpts.resubTimeoutMs` to the underlying `WebSocketAccountSubscriber`. Unlike other subscribers here, only this single option is exposed (not the full `ResubOpts` shape).
|
|
53
|
-
* @param commitment Commitment for the underlying subscription; defaults to the provider's configured commitment.
|
|
54
|
-
*/
|
|
55
|
-
public constructor(
|
|
56
|
-
program: VelocityProgram,
|
|
57
|
-
insuranceFundStakeAccountPublicKey: PublicKey,
|
|
58
|
-
resubTimeoutMs?: number,
|
|
59
|
-
commitment?: Commitment
|
|
60
|
-
) {
|
|
61
|
-
this.isSubscribed = false;
|
|
62
|
-
this.program = program;
|
|
63
|
-
this.insuranceFundStakeAccountPublicKey =
|
|
64
|
-
insuranceFundStakeAccountPublicKey;
|
|
65
|
-
this.eventEmitter = new EventEmitter();
|
|
66
|
-
this.resubTimeoutMs = resubTimeoutMs;
|
|
67
|
-
this.commitment = commitment;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Creates the underlying `WebSocketAccountSubscriber` and subscribes it. Idempotent: a no-op
|
|
72
|
-
* (returns `true`) if already subscribed.
|
|
73
|
-
* @param insuranceFundStakeAccount Optional pre-fetched account data to seed the subscriber with, skipping the initial RPC fetch.
|
|
74
|
-
*/
|
|
75
|
-
async subscribe(
|
|
76
|
-
insuranceFundStakeAccount?: InsuranceFundStake
|
|
77
|
-
): Promise<boolean> {
|
|
78
|
-
if (this.isSubscribed) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this.insuranceFundStakeDataAccountSubscriber =
|
|
83
|
-
new WebSocketAccountSubscriber(
|
|
84
|
-
'insuranceFundStake',
|
|
85
|
-
this.program,
|
|
86
|
-
this.insuranceFundStakeAccountPublicKey,
|
|
87
|
-
undefined,
|
|
88
|
-
{
|
|
89
|
-
resubTimeoutMs: this.resubTimeoutMs,
|
|
90
|
-
},
|
|
91
|
-
this.commitment
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
if (insuranceFundStakeAccount) {
|
|
95
|
-
this.insuranceFundStakeDataAccountSubscriber.setData(
|
|
96
|
-
insuranceFundStakeAccount
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
await this.insuranceFundStakeDataAccountSubscriber.subscribe(
|
|
101
|
-
(data: InsuranceFundStake) => {
|
|
102
|
-
this.eventEmitter.emit('insuranceFundStakeAccountUpdate', data);
|
|
103
|
-
this.eventEmitter.emit('update');
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
this.eventEmitter.emit('update');
|
|
108
|
-
this.isSubscribed = true;
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** Fetches the account once via the underlying `WebSocketAccountSubscriber`. */
|
|
113
|
-
async fetch(): Promise<void> {
|
|
114
|
-
await Promise.all([this.insuranceFundStakeDataAccountSubscriber.fetch()]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Tears down the underlying WebSocket subscription. A no-op if not subscribed. */
|
|
118
|
-
async unsubscribe(): Promise<void> {
|
|
119
|
-
if (!this.isSubscribed) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await Promise.all([
|
|
124
|
-
this.insuranceFundStakeDataAccountSubscriber.unsubscribe(),
|
|
125
|
-
]);
|
|
126
|
-
|
|
127
|
-
this.isSubscribed = false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** Throws `NotSubscribedError` if `subscribe()` has not been called. */
|
|
131
|
-
assertIsSubscribed(): void {
|
|
132
|
-
if (!this.isSubscribed) {
|
|
133
|
-
throw new NotSubscribedError(
|
|
134
|
-
'You must call `subscribe` before using this function'
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** Throws `NotSubscribedError` if not subscribed. Returns undefined only if subscribed but no data has loaded yet. */
|
|
140
|
-
public getInsuranceFundStakeAccountAndSlot():
|
|
141
|
-
| DataAndSlot<InsuranceFundStake>
|
|
142
|
-
| undefined {
|
|
143
|
-
this.assertIsSubscribed();
|
|
144
|
-
return this.insuranceFundStakeDataAccountSubscriber.dataAndSlot;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Applies an externally-obtained account update if `slot` is not older than the currently
|
|
149
|
-
* cached slot.
|
|
150
|
-
* @param insuranceFundStake Decoded account data to apply.
|
|
151
|
-
* @param slot Slot the data was observed at.
|
|
152
|
-
*/
|
|
153
|
-
public updateData(
|
|
154
|
-
insuranceFundStake: InsuranceFundStake,
|
|
155
|
-
slot: number
|
|
156
|
-
): void {
|
|
157
|
-
const currentDataSlot =
|
|
158
|
-
this.insuranceFundStakeDataAccountSubscriber.dataAndSlot?.slot || 0;
|
|
159
|
-
if (currentDataSlot <= slot) {
|
|
160
|
-
this.insuranceFundStakeDataAccountSubscriber.setData(
|
|
161
|
-
insuranceFundStake,
|
|
162
|
-
slot
|
|
163
|
-
);
|
|
164
|
-
this.eventEmitter.emit(
|
|
165
|
-
'insuranceFundStakeAccountUpdate',
|
|
166
|
-
insuranceFundStake
|
|
167
|
-
);
|
|
168
|
-
this.eventEmitter.emit('update');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|