@drift-labs/sdk 0.2.0-master.11 → 0.2.0-master.14
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/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +24 -3
- package/lib/clearingHouse.js +352 -51
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +15 -15
- package/lib/clearingHouseUser.js +185 -73
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +4 -3
- package/lib/constants/numericConstants.d.ts +2 -0
- package/lib/constants/numericConstants.js +3 -1
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +37 -11
- package/lib/idl/clearing_house.json +692 -58
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.js +2 -2
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +76 -1
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +43 -12
- package/lib/math/trade.js +2 -2
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +2 -77
- package/lib/tokenFaucet.d.ts +1 -0
- package/lib/tokenFaucet.js +23 -12
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/types.d.ts +78 -10
- package/lib/types.js +12 -0
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +1 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +29 -1
- package/src/clearingHouse.ts +619 -62
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +317 -105
- package/src/clearingHouseUserStats.ts +53 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +6 -3
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +3 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/types.ts +2 -0
- package/src/factory/bigNum.js +37 -11
- package/src/factory/bigNum.ts +43 -13
- package/src/idl/clearing_house.json +692 -58
- package/src/index.ts +1 -0
- package/src/math/amm.ts +8 -5
- package/src/math/bankBalance.ts +147 -1
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +60 -9
- package/src/math/trade.ts +2 -2
- package/src/orders.ts +4 -157
- package/src/tokenFaucet.js +189 -0
- package/src/tokenFaucet.ts +38 -15
- package/src/tx/retryTxSender.ts +11 -3
- package/src/types.js +12 -1
- package/src/types.ts +83 -10
- package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/tests/bn/test.ts +2 -0
- package/src/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/addresses/pda.js +0 -104
- package/src/index.js +0 -100
- package/src/math/bankBalance.js +0 -75
- package/src/math/market.js +0 -57
- package/src/math/orders.js +0 -110
- package/src/math/position.js +0 -140
- package/src/mockUSDCFaucet.js +0 -280
- package/src/orders.js +0 -134
- package/src/tx/retryTxSender.js +0 -188
package/lib/tokenFaucet.js
CHANGED
|
@@ -73,8 +73,8 @@ class TokenFaucet {
|
|
|
73
73
|
async fetchState() {
|
|
74
74
|
return await this.program.account.faucetConfig.fetch(await this.getFaucetConfigPublicKey());
|
|
75
75
|
}
|
|
76
|
-
async
|
|
77
|
-
return
|
|
76
|
+
async mintToUserIx(userTokenAccount, amount) {
|
|
77
|
+
return this.program.instruction.mintToUser(amount, {
|
|
78
78
|
accounts: {
|
|
79
79
|
faucetConfig: await this.getFaucetConfigPublicKey(),
|
|
80
80
|
mintAccount: this.mint,
|
|
@@ -84,6 +84,12 @@ class TokenFaucet {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
+
async mintToUser(userTokenAccount, amount) {
|
|
88
|
+
const mintIx = await this.mintToUserIx(userTokenAccount, amount);
|
|
89
|
+
const tx = new web3_js_1.Transaction().add(mintIx);
|
|
90
|
+
const txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
|
|
91
|
+
return txSig;
|
|
92
|
+
}
|
|
87
93
|
async transferMintAuthority() {
|
|
88
94
|
return await this.program.rpc.transferMintAuthority({
|
|
89
95
|
accounts: {
|
|
@@ -96,8 +102,21 @@ class TokenFaucet {
|
|
|
96
102
|
});
|
|
97
103
|
}
|
|
98
104
|
async createAssociatedTokenAccountAndMintTo(userPublicKey, amount) {
|
|
105
|
+
const tx = new web3_js_1.Transaction();
|
|
99
106
|
const [associatedTokenPublicKey, createAssociatedAccountIx, mintToTx] = await this.createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount);
|
|
100
|
-
|
|
107
|
+
let associatedTokenAccountExists = false;
|
|
108
|
+
try {
|
|
109
|
+
const assosciatedTokenAccount = await this.connection.getAccountInfo(associatedTokenPublicKey);
|
|
110
|
+
associatedTokenAccountExists = !!assosciatedTokenAccount;
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
// token account doesn't exist
|
|
114
|
+
associatedTokenAccountExists = false;
|
|
115
|
+
}
|
|
116
|
+
const skipAccountCreation = associatedTokenAccountExists;
|
|
117
|
+
if (!skipAccountCreation)
|
|
118
|
+
tx.add(createAssociatedAccountIx);
|
|
119
|
+
tx.add(mintToTx);
|
|
101
120
|
const txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
|
|
102
121
|
return [associatedTokenPublicKey, txSig];
|
|
103
122
|
}
|
|
@@ -105,15 +124,7 @@ class TokenFaucet {
|
|
|
105
124
|
const state = await this.fetchState();
|
|
106
125
|
const associateTokenPublicKey = await this.getAssosciatedMockUSDMintAddress({ userPubKey: userPublicKey });
|
|
107
126
|
const createAssociatedAccountIx = spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.mint, associateTokenPublicKey, userPublicKey, this.wallet.publicKey);
|
|
108
|
-
const mintToIx = await this.
|
|
109
|
-
accounts: {
|
|
110
|
-
faucetConfig: await this.getFaucetConfigPublicKey(),
|
|
111
|
-
mintAccount: state.mint,
|
|
112
|
-
userTokenAccount: associateTokenPublicKey,
|
|
113
|
-
mintAuthority: state.mintAuthority,
|
|
114
|
-
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
115
|
-
},
|
|
116
|
-
});
|
|
127
|
+
const mintToIx = await this.mintToUserIx(associateTokenPublicKey, amount);
|
|
117
128
|
return [associateTokenPublicKey, createAssociatedAccountIx, mintToIx];
|
|
118
129
|
}
|
|
119
130
|
async getAssosciatedMockUSDMintAddress(props) {
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -25,8 +25,15 @@ class RetryTxSender {
|
|
|
25
25
|
await this.prepareTx(tx, additionalSigners, opts);
|
|
26
26
|
const rawTransaction = tx.serialize();
|
|
27
27
|
const startTime = this.getTimestamp();
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
let txid;
|
|
29
|
+
try {
|
|
30
|
+
txid = await this.provider.connection.sendRawTransaction(rawTransaction, opts);
|
|
31
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
console.error(e);
|
|
35
|
+
throw e;
|
|
36
|
+
}
|
|
30
37
|
let done = false;
|
|
31
38
|
const resolveReference = {
|
|
32
39
|
resolve: undefined,
|
package/lib/types.d.ts
CHANGED
|
@@ -113,6 +113,12 @@ export declare class OrderActionExplanation {
|
|
|
113
113
|
static readonly MARKET_ORDER_FILLED_TO_LIMIT_PRICE: {
|
|
114
114
|
marketOrderFilledToLimitPrice: {};
|
|
115
115
|
};
|
|
116
|
+
static readonly CANCELED_FOR_LIQUIDATION: {
|
|
117
|
+
canceledForLiquidation: {};
|
|
118
|
+
};
|
|
119
|
+
static readonly MARKET_ORDER_AUCTION_EXPIRED: {
|
|
120
|
+
marketOrderAuctionExpired: {};
|
|
121
|
+
};
|
|
116
122
|
}
|
|
117
123
|
export declare class OrderTriggerCondition {
|
|
118
124
|
static readonly ABOVE: {
|
|
@@ -192,10 +198,13 @@ export declare type LiquidationRecord = {
|
|
|
192
198
|
liquidationType: LiquidationType;
|
|
193
199
|
marginRequirement: BN;
|
|
194
200
|
totalCollateral: BN;
|
|
201
|
+
liquidationId: number;
|
|
195
202
|
liquidatePerp: LiquidatePerpRecord;
|
|
196
203
|
liquidateBorrow: LiquidateBorrowRecord;
|
|
197
204
|
liquidateBorrowForPerpPnl: LiquidateBorrowForPerpPnlRecord;
|
|
198
205
|
liquidatePerpPnlForDeposit: LiquidatePerpPnlForDepositRecord;
|
|
206
|
+
perpBankruptcy: PerpBankruptcyRecord;
|
|
207
|
+
borrowBankruptcy: BorrowBankruptcyRecord;
|
|
199
208
|
};
|
|
200
209
|
export declare class LiquidationType {
|
|
201
210
|
static readonly LIQUIDATE_PERP: {
|
|
@@ -210,6 +219,12 @@ export declare class LiquidationType {
|
|
|
210
219
|
static readonly LIQUIDATE_PERP_PNL_FOR_DEPOSIT: {
|
|
211
220
|
liquidatePerpPnlForDeposit: {};
|
|
212
221
|
};
|
|
222
|
+
static readonly PERP_BANKRUPTCY: {
|
|
223
|
+
perpBankruptcy: {};
|
|
224
|
+
};
|
|
225
|
+
static readonly BORROW_BANKRUPTCY: {
|
|
226
|
+
borrowBankruptcy: {};
|
|
227
|
+
};
|
|
213
228
|
}
|
|
214
229
|
export declare type LiquidatePerpRecord = {
|
|
215
230
|
marketIndex: BN;
|
|
@@ -248,14 +263,34 @@ export declare type LiquidatePerpPnlForDepositRecord = {
|
|
|
248
263
|
assetPrice: BN;
|
|
249
264
|
assetTransfer: BN;
|
|
250
265
|
};
|
|
266
|
+
export declare type PerpBankruptcyRecord = {
|
|
267
|
+
marketIndex: BN;
|
|
268
|
+
pnl: BN;
|
|
269
|
+
cumulativeFundingRateDelta: BN;
|
|
270
|
+
};
|
|
271
|
+
export declare type BorrowBankruptcyRecord = {
|
|
272
|
+
bankIndex: BN;
|
|
273
|
+
borrowAmount: BN;
|
|
274
|
+
cumulativeDepositInterestDelta: BN;
|
|
275
|
+
};
|
|
276
|
+
export declare type SettlePnlRecord = {
|
|
277
|
+
ts: BN;
|
|
278
|
+
user: PublicKey;
|
|
279
|
+
marketIndex: BN;
|
|
280
|
+
pnl: BN;
|
|
281
|
+
baseAssetAmount: BN;
|
|
282
|
+
quoteAssetAmountAfter: BN;
|
|
283
|
+
quoteEntryamount: BN;
|
|
284
|
+
settlePrice: BN;
|
|
285
|
+
};
|
|
251
286
|
export declare type OrderRecord = {
|
|
252
287
|
ts: BN;
|
|
253
288
|
taker: PublicKey;
|
|
254
289
|
maker: PublicKey;
|
|
255
290
|
takerOrder: Order;
|
|
256
291
|
makerOrder: Order;
|
|
257
|
-
|
|
258
|
-
|
|
292
|
+
takerPnl: BN;
|
|
293
|
+
makerPnl: BN;
|
|
259
294
|
action: OrderAction;
|
|
260
295
|
actionExplanation: OrderActionExplanation;
|
|
261
296
|
filler: PublicKey;
|
|
@@ -313,6 +348,10 @@ export declare type MarketAccount = {
|
|
|
313
348
|
nextFillRecordId: BN;
|
|
314
349
|
pnlPool: PoolBalance;
|
|
315
350
|
liquidationFee: BN;
|
|
351
|
+
imfFactor: BN;
|
|
352
|
+
unsettledImfFactor: BN;
|
|
353
|
+
unsettledInitialAssetWeight: number;
|
|
354
|
+
unsettledMaintenanceAssetWeight: number;
|
|
316
355
|
};
|
|
317
356
|
export declare type BankAccount = {
|
|
318
357
|
bankIndex: BN;
|
|
@@ -336,6 +375,11 @@ export declare type BankAccount = {
|
|
|
336
375
|
initialLiabilityWeight: BN;
|
|
337
376
|
maintenanceLiabilityWeight: BN;
|
|
338
377
|
liquidationFee: BN;
|
|
378
|
+
imfFactor: BN;
|
|
379
|
+
withdrawGuardThreshold: BN;
|
|
380
|
+
depositTokenTwap: BN;
|
|
381
|
+
borrowTokenTwap: BN;
|
|
382
|
+
utilizationTwap: BN;
|
|
339
383
|
};
|
|
340
384
|
export declare type PoolBalance = {
|
|
341
385
|
balance: BN;
|
|
@@ -347,8 +391,10 @@ export declare type AMM = {
|
|
|
347
391
|
lastFundingRate: BN;
|
|
348
392
|
lastFundingRateTs: BN;
|
|
349
393
|
lastMarkPriceTwap: BN;
|
|
394
|
+
lastMarkPriceTwap5min: BN;
|
|
350
395
|
lastMarkPriceTwapTs: BN;
|
|
351
396
|
lastOraclePriceTwap: BN;
|
|
397
|
+
lastOraclePriceTwap5min: BN;
|
|
352
398
|
lastOraclePriceTwapTs: BN;
|
|
353
399
|
lastOracleMarkSpreadPct: BN;
|
|
354
400
|
lastOracleConfPct: BN;
|
|
@@ -359,11 +405,16 @@ export declare type AMM = {
|
|
|
359
405
|
pegMultiplier: BN;
|
|
360
406
|
cumulativeFundingRateLong: BN;
|
|
361
407
|
cumulativeFundingRateShort: BN;
|
|
408
|
+
cumulativeFundingRateLp: BN;
|
|
362
409
|
cumulativeRepegRebateLong: BN;
|
|
363
410
|
cumulativeRepegRebateShort: BN;
|
|
364
411
|
totalFeeMinusDistributions: BN;
|
|
365
412
|
totalFeeWithdrawn: BN;
|
|
366
413
|
totalFee: BN;
|
|
414
|
+
cumulativeFundingPaymentPerLp: BN;
|
|
415
|
+
cumulativeFeePerLp: BN;
|
|
416
|
+
cumulativeNetBaseAssetAmountPerLp: BN;
|
|
417
|
+
userLpShares: BN;
|
|
367
418
|
minimumQuoteAssetTradeSize: BN;
|
|
368
419
|
baseAssetAmountStepSize: BN;
|
|
369
420
|
maxBaseAssetAmountRatio: number;
|
|
@@ -385,6 +436,8 @@ export declare type AMM = {
|
|
|
385
436
|
longSpread: BN;
|
|
386
437
|
shortSpread: BN;
|
|
387
438
|
maxSpread: number;
|
|
439
|
+
marketPosition: UserPosition;
|
|
440
|
+
marketPositionPerLp: UserPosition;
|
|
388
441
|
};
|
|
389
442
|
export declare type UserPosition = {
|
|
390
443
|
baseAssetAmount: BN;
|
|
@@ -393,17 +446,22 @@ export declare type UserPosition = {
|
|
|
393
446
|
quoteAssetAmount: BN;
|
|
394
447
|
quoteEntryAmount: BN;
|
|
395
448
|
openOrders: BN;
|
|
396
|
-
unsettledPnl: BN;
|
|
397
449
|
openBids: BN;
|
|
398
450
|
openAsks: BN;
|
|
451
|
+
realizedPnl: BN;
|
|
452
|
+
lpShares: BN;
|
|
453
|
+
lastFeePerLp: BN;
|
|
454
|
+
lastNetBaseAssetAmountPerLp: BN;
|
|
455
|
+
lastNetQuoteAssetAmountPerLp: BN;
|
|
399
456
|
};
|
|
400
|
-
export declare type
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
457
|
+
export declare type UserStatsAccount = {
|
|
458
|
+
numberOfUsers: number;
|
|
459
|
+
makerVolume30D: BN;
|
|
460
|
+
takerVolume30D: BN;
|
|
461
|
+
fillerVolume30D: BN;
|
|
462
|
+
lastMakerVolume30DTs: BN;
|
|
463
|
+
lastTakerVolume30DTs: BN;
|
|
464
|
+
lastFillerVolume30DTs: BN;
|
|
407
465
|
fees: {
|
|
408
466
|
totalFeePaid: BN;
|
|
409
467
|
totalFeeRebate: BN;
|
|
@@ -411,9 +469,17 @@ export declare type UserAccount = {
|
|
|
411
469
|
totalReferralReward: BN;
|
|
412
470
|
totalRefereeDiscount: BN;
|
|
413
471
|
};
|
|
472
|
+
};
|
|
473
|
+
export declare type UserAccount = {
|
|
474
|
+
authority: PublicKey;
|
|
475
|
+
name: number[];
|
|
476
|
+
userId: number;
|
|
477
|
+
bankBalances: UserBankBalance[];
|
|
414
478
|
positions: UserPosition[];
|
|
415
479
|
orders: Order[];
|
|
416
480
|
beingLiquidated: boolean;
|
|
481
|
+
bankrupt: boolean;
|
|
482
|
+
nextLiquidationId: number;
|
|
417
483
|
};
|
|
418
484
|
export declare type UserBankBalance = {
|
|
419
485
|
bankIndex: BN;
|
|
@@ -508,10 +574,12 @@ export declare const DefaultOrderParams: {
|
|
|
508
574
|
};
|
|
509
575
|
export declare type MakerInfo = {
|
|
510
576
|
maker: PublicKey;
|
|
577
|
+
makerStats: PublicKey;
|
|
511
578
|
order: Order;
|
|
512
579
|
};
|
|
513
580
|
export declare type TakerInfo = {
|
|
514
581
|
taker: PublicKey;
|
|
582
|
+
takerStats: PublicKey;
|
|
515
583
|
order: Order;
|
|
516
584
|
};
|
|
517
585
|
export interface IWallet {
|
package/lib/types.js
CHANGED
|
@@ -70,6 +70,12 @@ OrderActionExplanation.ORACLE_PRICE_BREACHED_LIMIT_PRICE = {
|
|
|
70
70
|
OrderActionExplanation.MARKET_ORDER_FILLED_TO_LIMIT_PRICE = {
|
|
71
71
|
marketOrderFilledToLimitPrice: {},
|
|
72
72
|
};
|
|
73
|
+
OrderActionExplanation.CANCELED_FOR_LIQUIDATION = {
|
|
74
|
+
canceledForLiquidation: {},
|
|
75
|
+
};
|
|
76
|
+
OrderActionExplanation.MARKET_ORDER_AUCTION_EXPIRED = {
|
|
77
|
+
marketOrderAuctionExpired: {},
|
|
78
|
+
};
|
|
73
79
|
class OrderTriggerCondition {
|
|
74
80
|
}
|
|
75
81
|
exports.OrderTriggerCondition = OrderTriggerCondition;
|
|
@@ -102,6 +108,12 @@ LiquidationType.LIQUIDATE_BORROW_FOR_PERP_PNL = {
|
|
|
102
108
|
LiquidationType.LIQUIDATE_PERP_PNL_FOR_DEPOSIT = {
|
|
103
109
|
liquidatePerpPnlForDeposit: {},
|
|
104
110
|
};
|
|
111
|
+
LiquidationType.PERP_BANKRUPTCY = {
|
|
112
|
+
perpBankruptcy: {},
|
|
113
|
+
};
|
|
114
|
+
LiquidationType.BORROW_BANKRUPTCY = {
|
|
115
|
+
borrowBankruptcy: {},
|
|
116
|
+
};
|
|
105
117
|
exports.DefaultOrderParams = {
|
|
106
118
|
orderType: OrderType.MARKET,
|
|
107
119
|
userOrderId: 0,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTokenAddress = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const getTokenAddress = (mintAddress, userPubKey) => {
|
|
7
|
+
return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
|
|
8
|
+
};
|
|
9
|
+
exports.getTokenAddress = getTokenAddress;
|
package/package.json
CHANGED
package/src/accounts/fetch.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
-
import { UserAccount } from '../types';
|
|
3
|
-
import {
|
|
2
|
+
import { UserAccount, UserStatsAccount } from '../types';
|
|
3
|
+
import {
|
|
4
|
+
getUserAccountPublicKey,
|
|
5
|
+
getUserStatsAccountPublicKey,
|
|
6
|
+
} from '../addresses/pda';
|
|
4
7
|
import { Program } from '@project-serum/anchor';
|
|
5
8
|
|
|
6
9
|
export async function fetchUserAccounts(
|
|
@@ -31,3 +34,25 @@ export async function fetchUserAccounts(
|
|
|
31
34
|
) as UserAccount;
|
|
32
35
|
});
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
export async function fetchUserStatsAccount(
|
|
39
|
+
connection: Connection,
|
|
40
|
+
program: Program,
|
|
41
|
+
authority: PublicKey
|
|
42
|
+
): Promise<UserStatsAccount | undefined> {
|
|
43
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
44
|
+
program.programId,
|
|
45
|
+
authority
|
|
46
|
+
);
|
|
47
|
+
const accountInfo = await connection.getAccountInfo(
|
|
48
|
+
userStatsPublicKey,
|
|
49
|
+
'confirmed'
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return accountInfo
|
|
53
|
+
? (program.account.user.coder.accounts.decode(
|
|
54
|
+
'UserStats',
|
|
55
|
+
accountInfo.data
|
|
56
|
+
) as UserStatsAccount)
|
|
57
|
+
: undefined;
|
|
58
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
AccountToPoll,
|
|
4
|
+
NotSubscribedError,
|
|
5
|
+
UserStatsAccountSubscriber,
|
|
6
|
+
UserStatsAccountEvents,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { Program } from '@project-serum/anchor';
|
|
9
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { PublicKey } from '@solana/web3.js';
|
|
12
|
+
import { UserStatsAccount } from '../types';
|
|
13
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
14
|
+
import { capitalize } from './utils';
|
|
15
|
+
|
|
16
|
+
export class PollingUserStatsAccountSubscriber
|
|
17
|
+
implements UserStatsAccountSubscriber
|
|
18
|
+
{
|
|
19
|
+
isSubscribed: boolean;
|
|
20
|
+
program: Program;
|
|
21
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
22
|
+
userStatsAccountPublicKey: PublicKey;
|
|
23
|
+
|
|
24
|
+
accountLoader: BulkAccountLoader;
|
|
25
|
+
accountsToPoll = new Map<string, AccountToPoll>();
|
|
26
|
+
errorCallbackId?: string;
|
|
27
|
+
|
|
28
|
+
userStats?: DataAndSlot<UserStatsAccount>;
|
|
29
|
+
|
|
30
|
+
public constructor(
|
|
31
|
+
program: Program,
|
|
32
|
+
userStatsAccountPublicKey: PublicKey,
|
|
33
|
+
accountLoader: BulkAccountLoader
|
|
34
|
+
) {
|
|
35
|
+
this.isSubscribed = false;
|
|
36
|
+
this.program = program;
|
|
37
|
+
this.accountLoader = accountLoader;
|
|
38
|
+
this.eventEmitter = new EventEmitter();
|
|
39
|
+
this.userStatsAccountPublicKey = userStatsAccountPublicKey;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async subscribe(): Promise<boolean> {
|
|
43
|
+
if (this.isSubscribed) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.addToAccountLoader();
|
|
48
|
+
|
|
49
|
+
let subscriptionSucceeded = false;
|
|
50
|
+
let retries = 0;
|
|
51
|
+
while (!subscriptionSucceeded && retries < 5) {
|
|
52
|
+
await this.fetchIfUnloaded();
|
|
53
|
+
subscriptionSucceeded = this.didSubscriptionSucceed();
|
|
54
|
+
retries++;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (subscriptionSucceeded) {
|
|
58
|
+
this.eventEmitter.emit('update');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isSubscribed = subscriptionSucceeded;
|
|
62
|
+
return subscriptionSucceeded;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async addToAccountLoader(): Promise<void> {
|
|
66
|
+
if (this.accountsToPoll.size > 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
|
|
71
|
+
key: 'userStats',
|
|
72
|
+
publicKey: this.userStatsAccountPublicKey,
|
|
73
|
+
eventType: 'userStatsAccountUpdate',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
77
|
+
accountToPoll.callbackId = this.accountLoader.addAccount(
|
|
78
|
+
accountToPoll.publicKey,
|
|
79
|
+
(buffer, slot) => {
|
|
80
|
+
if (!buffer) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const account = this.program.account[
|
|
85
|
+
accountToPoll.key
|
|
86
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
87
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
this.eventEmitter.emit(accountToPoll.eventType, account);
|
|
90
|
+
this.eventEmitter.emit('update');
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
96
|
+
this.eventEmitter.emit('error', error);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async fetchIfUnloaded(): Promise<void> {
|
|
101
|
+
let shouldFetch = false;
|
|
102
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
103
|
+
if (this[accountToPoll.key] === undefined) {
|
|
104
|
+
shouldFetch = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (shouldFetch) {
|
|
110
|
+
await this.fetch();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async fetch(): Promise<void> {
|
|
115
|
+
await this.accountLoader.load();
|
|
116
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
117
|
+
const { buffer, slot } = this.accountLoader.getBufferAndSlot(
|
|
118
|
+
accountToPoll.publicKey
|
|
119
|
+
);
|
|
120
|
+
if (buffer) {
|
|
121
|
+
const account = this.program.account[
|
|
122
|
+
accountToPoll.key
|
|
123
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
124
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
didSubscriptionSucceed(): boolean {
|
|
130
|
+
let success = true;
|
|
131
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
132
|
+
if (!this[accountToPoll.key]) {
|
|
133
|
+
success = false;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return success;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async unsubscribe(): Promise<void> {
|
|
141
|
+
if (!this.isSubscribed) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
146
|
+
this.accountLoader.removeAccount(
|
|
147
|
+
accountToPoll.publicKey,
|
|
148
|
+
accountToPoll.callbackId
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
153
|
+
this.errorCallbackId = undefined;
|
|
154
|
+
|
|
155
|
+
this.accountsToPoll.clear();
|
|
156
|
+
|
|
157
|
+
this.isSubscribed = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
assertIsSubscribed(): void {
|
|
161
|
+
if (!this.isSubscribed) {
|
|
162
|
+
throw new NotSubscribedError(
|
|
163
|
+
'You must call `subscribe` before using this function'
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
|
|
169
|
+
this.assertIsSubscribed();
|
|
170
|
+
return this.userStats;
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
OracleSource,
|
|
5
5
|
StateAccount,
|
|
6
6
|
UserAccount,
|
|
7
|
+
UserStatsAccount,
|
|
7
8
|
} from '../types';
|
|
8
9
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
9
10
|
import { EventEmitter } from 'events';
|
|
@@ -130,3 +131,20 @@ export type DataAndSlot<T> = {
|
|
|
130
131
|
data: T;
|
|
131
132
|
slot: number;
|
|
132
133
|
};
|
|
134
|
+
|
|
135
|
+
export interface UserStatsAccountEvents {
|
|
136
|
+
userStatsAccountUpdate: (payload: UserStatsAccount) => void;
|
|
137
|
+
update: void;
|
|
138
|
+
error: (e: Error) => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface UserStatsAccountSubscriber {
|
|
142
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
143
|
+
isSubscribed: boolean;
|
|
144
|
+
|
|
145
|
+
subscribe(): Promise<boolean>;
|
|
146
|
+
fetch(): Promise<void>;
|
|
147
|
+
unsubscribe(): Promise<void>;
|
|
148
|
+
|
|
149
|
+
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
150
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
AccountSubscriber,
|
|
4
|
+
NotSubscribedError,
|
|
5
|
+
UserStatsAccountSubscriber,
|
|
6
|
+
UserStatsAccountEvents,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { Program } from '@project-serum/anchor';
|
|
9
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { PublicKey } from '@solana/web3.js';
|
|
12
|
+
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
13
|
+
import { UserStatsAccount } from '../types';
|
|
14
|
+
|
|
15
|
+
export class WebSocketUserStatsAccountSubscriber
|
|
16
|
+
implements UserStatsAccountSubscriber
|
|
17
|
+
{
|
|
18
|
+
isSubscribed: boolean;
|
|
19
|
+
program: Program;
|
|
20
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
21
|
+
userStatsAccountPublicKey: PublicKey;
|
|
22
|
+
|
|
23
|
+
userStatsAccountSubscriber: AccountSubscriber<UserStatsAccount>;
|
|
24
|
+
|
|
25
|
+
public constructor(program: Program, userStatsAccountPublicKey: PublicKey) {
|
|
26
|
+
this.isSubscribed = false;
|
|
27
|
+
this.program = program;
|
|
28
|
+
this.userStatsAccountPublicKey = userStatsAccountPublicKey;
|
|
29
|
+
this.eventEmitter = new EventEmitter();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async subscribe(): Promise<boolean> {
|
|
33
|
+
if (this.isSubscribed) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.userStatsAccountSubscriber = new WebSocketAccountSubscriber(
|
|
38
|
+
'userStats',
|
|
39
|
+
this.program,
|
|
40
|
+
this.userStatsAccountPublicKey
|
|
41
|
+
);
|
|
42
|
+
await this.userStatsAccountSubscriber.subscribe(
|
|
43
|
+
(data: UserStatsAccount) => {
|
|
44
|
+
this.eventEmitter.emit('userStatsAccountUpdate', data);
|
|
45
|
+
this.eventEmitter.emit('update');
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.eventEmitter.emit('update');
|
|
50
|
+
this.isSubscribed = true;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async fetch(): Promise<void> {
|
|
55
|
+
await Promise.all([this.userStatsAccountSubscriber.fetch()]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async unsubscribe(): Promise<void> {
|
|
59
|
+
if (!this.isSubscribed) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await Promise.all([this.userStatsAccountSubscriber.unsubscribe()]);
|
|
64
|
+
|
|
65
|
+
this.isSubscribed = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
assertIsSubscribed(): void {
|
|
69
|
+
if (!this.isSubscribed) {
|
|
70
|
+
throw new NotSubscribedError(
|
|
71
|
+
'You must call `subscribe` before using this function'
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
|
|
77
|
+
this.assertIsSubscribed();
|
|
78
|
+
return this.userStatsAccountSubscriber.dataAndSlot;
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/addresses/pda.ts
CHANGED
|
@@ -57,6 +57,19 @@ export function getUserAccountPublicKeySync(
|
|
|
57
57
|
)[0];
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export function getUserStatsAccountPublicKey(
|
|
61
|
+
programId: PublicKey,
|
|
62
|
+
authority: PublicKey
|
|
63
|
+
): PublicKey {
|
|
64
|
+
return anchor.web3.PublicKey.findProgramAddressSync(
|
|
65
|
+
[
|
|
66
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('user_stats')),
|
|
67
|
+
authority.toBuffer(),
|
|
68
|
+
],
|
|
69
|
+
programId
|
|
70
|
+
)[0];
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
export async function getMarketPublicKey(
|
|
61
74
|
programId: PublicKey,
|
|
62
75
|
marketIndex: BN
|