@drift-labs/sdk 2.85.0-beta.0 → 2.85.0-beta.10
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/VERSION +1 -1
- package/bun.lockb +0 -0
- package/lib/accounts/bulkAccountLoader.d.ts +3 -3
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +10 -2
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +4 -3
- package/lib/accounts/pollingUserAccountSubscriber.js +7 -6
- package/lib/accounts/testBulkAccountLoader.d.ts +4 -0
- package/lib/accounts/testBulkAccountLoader.js +45 -0
- package/lib/bankrun/bankrunConnection.d.ts +71 -0
- package/lib/bankrun/bankrunConnection.js +285 -0
- package/lib/blockhashSubscriber/BlockhashSubscriber.js +22 -15
- package/lib/constants/perpMarkets.js +10 -0
- package/lib/constants/spotMarkets.js +10 -0
- package/lib/driftClient.d.ts +2 -2
- package/lib/driftClient.js +14 -13
- package/lib/events/eventSubscriber.js +12 -4
- package/lib/idl/drift.json +28 -8
- package/lib/testClient.js +1 -2
- package/lib/tokenFaucet.d.ts +3 -1
- package/lib/tokenFaucet.js +41 -8
- package/lib/tx/txParamProcessor.d.ts +2 -1
- package/lib/tx/txParamProcessor.js +7 -3
- package/lib/types.d.ts +1 -0
- package/lib/user.js +1 -1
- package/package.json +3 -1
- package/src/accounts/bulkAccountLoader.ts +3 -2
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +16 -3
- package/src/accounts/pollingUserAccountSubscriber.ts +13 -12
- package/src/accounts/testBulkAccountLoader.ts +53 -0
- package/src/bankrun/bankrunConnection.ts +466 -0
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +24 -19
- package/src/constants/perpMarkets.ts +10 -0
- package/src/constants/spotMarkets.ts +10 -0
- package/src/driftClient.ts +21 -15
- package/src/events/eventSubscriber.ts +5 -0
- package/src/idl/drift.json +28 -8
- package/src/testClient.ts +1 -2
- package/src/tokenFaucet.ts +49 -12
- package/src/tx/txParamProcessor.ts +11 -2
- package/src/types.ts +1 -0
- package/src/user.ts +5 -2
package/lib/driftClient.js
CHANGED
|
@@ -2267,6 +2267,9 @@ class DriftClient {
|
|
|
2267
2267
|
async getJupiterSwapIxV6({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, quote, reduceOnly, userAccountPublicKey, }) {
|
|
2268
2268
|
const outMarket = this.getSpotMarketAccount(outMarketIndex);
|
|
2269
2269
|
const inMarket = this.getSpotMarketAccount(inMarketIndex);
|
|
2270
|
+
const isExactOut = swapMode === 'ExactOut' || quote.swapMode === 'ExactOut';
|
|
2271
|
+
const amountIn = new anchor_1.BN(quote.inAmount);
|
|
2272
|
+
const exactOutBufferedAmountIn = amountIn.muln(1001).divn(1000); // Add 10bp buffer
|
|
2270
2273
|
if (!quote) {
|
|
2271
2274
|
const fetchedQuote = await jupiterClient.getQuote({
|
|
2272
2275
|
inputMint: inMarket.mint,
|
|
@@ -2312,7 +2315,7 @@ class DriftClient {
|
|
|
2312
2315
|
const { beginSwapIx, endSwapIx } = await this.getSwapIx({
|
|
2313
2316
|
outMarketIndex,
|
|
2314
2317
|
inMarketIndex,
|
|
2315
|
-
amountIn:
|
|
2318
|
+
amountIn: isExactOut ? exactOutBufferedAmountIn : amountIn,
|
|
2316
2319
|
inTokenAccount: inAssociatedTokenAccount,
|
|
2317
2320
|
outTokenAccount: outAssociatedTokenAccount,
|
|
2318
2321
|
reduceOnly,
|
|
@@ -2544,7 +2547,7 @@ class DriftClient {
|
|
|
2544
2547
|
};
|
|
2545
2548
|
if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
|
|
2546
2549
|
const placeAndTakeTxToSim = (await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, true, recentBlockHash));
|
|
2547
|
-
const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_a = txParams.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : 1.2);
|
|
2550
|
+
const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_a = txParams.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : 1.2, txParams.lowerBoundCu);
|
|
2548
2551
|
if (shouldExitIfSimulationFails && !simulationResult.success) {
|
|
2549
2552
|
earlyExitFailedPlaceAndTakeSim = true;
|
|
2550
2553
|
return;
|
|
@@ -2586,6 +2589,9 @@ class DriftClient {
|
|
|
2586
2589
|
}
|
|
2587
2590
|
async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails) {
|
|
2588
2591
|
const txsToSign = await this.preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams, txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails);
|
|
2592
|
+
if (!txsToSign) {
|
|
2593
|
+
return null;
|
|
2594
|
+
}
|
|
2589
2595
|
const signedTxs = (await this.txHandler.getSignedTransactionMap(txsToSign, this.provider.wallet)).signedTxMap;
|
|
2590
2596
|
const { txSig, slot } = await this.sendTransaction(signedTxs.placeAndTakeTx, [], this.opts, true);
|
|
2591
2597
|
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
@@ -3318,12 +3324,12 @@ class DriftClient {
|
|
|
3318
3324
|
},
|
|
3319
3325
|
});
|
|
3320
3326
|
}
|
|
3321
|
-
async getAddInsuranceFundStakeIx(marketIndex, amount, collateralAccountPublicKey) {
|
|
3327
|
+
async getAddInsuranceFundStakeIx(marketIndex, amount, collateralAccountPublicKey, fromSubAccount) {
|
|
3322
3328
|
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
3323
3329
|
const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
|
|
3324
3330
|
const remainingAccounts = this.getRemainingAccounts({
|
|
3325
|
-
userAccounts: [this.getUserAccount()],
|
|
3326
|
-
useMarketLastSlotCache: true,
|
|
3331
|
+
userAccounts: fromSubAccount ? [this.getUserAccount()] : [],
|
|
3332
|
+
useMarketLastSlotCache: fromSubAccount ? true : false,
|
|
3327
3333
|
writableSpotMarketIndexes: [marketIndex],
|
|
3328
3334
|
});
|
|
3329
3335
|
const ix = this.program.instruction.addInsuranceFundStake(marketIndex, amount, {
|
|
@@ -3371,7 +3377,7 @@ class DriftClient {
|
|
|
3371
3377
|
const initializeIx = await this.getInitializeInsuranceFundStakeIx(marketIndex);
|
|
3372
3378
|
addIfStakeIxs.push(initializeIx);
|
|
3373
3379
|
}
|
|
3374
|
-
const addFundsIx = await this.getAddInsuranceFundStakeIx(marketIndex, amount, tokenAccount);
|
|
3380
|
+
const addFundsIx = await this.getAddInsuranceFundStakeIx(marketIndex, amount, tokenAccount, fromSubaccount);
|
|
3375
3381
|
addIfStakeIxs.push(addFundsIx);
|
|
3376
3382
|
if (createWSOLTokenAccount) {
|
|
3377
3383
|
addIfStakeIxs.push((0, spl_token_1.createCloseAccountInstruction)(tokenAccount, this.wallet.publicKey, this.wallet.publicKey, []));
|
|
@@ -3384,8 +3390,7 @@ class DriftClient {
|
|
|
3384
3390
|
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3385
3391
|
const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
|
|
3386
3392
|
const remainingAccounts = this.getRemainingAccounts({
|
|
3387
|
-
userAccounts: [
|
|
3388
|
-
useMarketLastSlotCache: true,
|
|
3393
|
+
userAccounts: [],
|
|
3389
3394
|
writableSpotMarketIndexes: [marketIndex],
|
|
3390
3395
|
});
|
|
3391
3396
|
const ix = await this.program.instruction.requestRemoveInsuranceFundStake(marketIndex, amount, {
|
|
@@ -3427,7 +3432,6 @@ class DriftClient {
|
|
|
3427
3432
|
return txSig;
|
|
3428
3433
|
}
|
|
3429
3434
|
async removeInsuranceFundStake(marketIndex, collateralAccountPublicKey, txParams) {
|
|
3430
|
-
var _a, _b;
|
|
3431
3435
|
const removeIfStakeIxs = [];
|
|
3432
3436
|
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3433
3437
|
const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
|
|
@@ -3450,11 +3454,8 @@ class DriftClient {
|
|
|
3450
3454
|
removeIfStakeIxs.push(createTokenAccountIx);
|
|
3451
3455
|
}
|
|
3452
3456
|
}
|
|
3453
|
-
const userAccountExists = !!((_b = (_a = this.getUser()) === null || _a === void 0 ? void 0 : _a.accountSubscriber) === null || _b === void 0 ? void 0 : _b.isSubscribed) &&
|
|
3454
|
-
(await this.checkIfAccountExists(this.getUser().userAccountPublicKey));
|
|
3455
3457
|
const remainingAccounts = this.getRemainingAccounts({
|
|
3456
|
-
userAccounts:
|
|
3457
|
-
useMarketLastSlotCache: false,
|
|
3458
|
+
userAccounts: [],
|
|
3458
3459
|
writableSpotMarketIndexes: [marketIndex],
|
|
3459
3460
|
});
|
|
3460
3461
|
const removeStakeIx = await this.program.instruction.removeInsuranceFundStake(marketIndex, {
|
|
@@ -24,10 +24,14 @@ class EventSubscriber {
|
|
|
24
24
|
this.eventListMap = new Map();
|
|
25
25
|
this.eventEmitter = new events_1.EventEmitter();
|
|
26
26
|
if (this.options.logProviderConfig.type === 'websocket') {
|
|
27
|
-
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(
|
|
27
|
+
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
this.connection, this.address, this.options.commitment, this.options.logProviderConfig.resubTimeoutMs);
|
|
28
30
|
}
|
|
29
31
|
else {
|
|
30
|
-
this.logProvider = new pollingLogProvider_1.PollingLogProvider(
|
|
32
|
+
this.logProvider = new pollingLogProvider_1.PollingLogProvider(
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
this.connection, this.address, options.commitment, this.options.logProviderConfig.frequency, this.options.logProviderConfig.batchSize);
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
populateInitialEventListMap() {
|
|
@@ -52,7 +56,9 @@ class EventSubscriber {
|
|
|
52
56
|
console.log('Failing over to polling');
|
|
53
57
|
this.logProvider.eventEmitter.removeAllListeners('reconnect');
|
|
54
58
|
this.unsubscribe().then(() => {
|
|
55
|
-
this.logProvider = new pollingLogProvider_1.PollingLogProvider(
|
|
59
|
+
this.logProvider = new pollingLogProvider_1.PollingLogProvider(
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
this.connection, this.address, this.options.commitment, logProviderConfig.fallbackFrequency, logProviderConfig.fallbackBatchSize);
|
|
56
62
|
this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime) => {
|
|
57
63
|
this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime);
|
|
58
64
|
}, true);
|
|
@@ -108,7 +114,9 @@ class EventSubscriber {
|
|
|
108
114
|
let beforeTx = undefined;
|
|
109
115
|
const untilTx = this.options.untilTx;
|
|
110
116
|
while (txFetched < this.options.maxTx) {
|
|
111
|
-
const response = await (0, fetchLogs_1.fetchLogs)(
|
|
117
|
+
const response = await (0, fetchLogs_1.fetchLogs)(
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
this.connection, this.address, this.options.commitment === 'finalized' ? 'finalized' : 'confirmed', beforeTx, untilTx);
|
|
112
120
|
if (response === undefined) {
|
|
113
121
|
break;
|
|
114
122
|
}
|
package/lib/idl/drift.json
CHANGED
|
@@ -3934,6 +3934,12 @@
|
|
|
3934
3934
|
{
|
|
3935
3935
|
"name": "maxBorrowRate",
|
|
3936
3936
|
"type": "u32"
|
|
3937
|
+
},
|
|
3938
|
+
{
|
|
3939
|
+
"name": "minBorrowRate",
|
|
3940
|
+
"type": {
|
|
3941
|
+
"option": "u8"
|
|
3942
|
+
}
|
|
3937
3943
|
}
|
|
3938
3944
|
]
|
|
3939
3945
|
},
|
|
@@ -6198,13 +6204,13 @@
|
|
|
6198
6204
|
"type": "i16"
|
|
6199
6205
|
},
|
|
6200
6206
|
{
|
|
6201
|
-
"name": "
|
|
6202
|
-
"
|
|
6203
|
-
"
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6207
|
+
"name": "maxTokenBorrowsFraction",
|
|
6208
|
+
"docs": [
|
|
6209
|
+
"What fraction of max_token_deposits",
|
|
6210
|
+
"disabled when 0, 1 => 1/10000 => .01% of max_token_deposits",
|
|
6211
|
+
"precision: X/10000"
|
|
6212
|
+
],
|
|
6213
|
+
"type": "u16"
|
|
6208
6214
|
},
|
|
6209
6215
|
{
|
|
6210
6216
|
"name": "flashLoanAmount",
|
|
@@ -6240,12 +6246,21 @@
|
|
|
6240
6246
|
],
|
|
6241
6247
|
"type": "u64"
|
|
6242
6248
|
},
|
|
6249
|
+
{
|
|
6250
|
+
"name": "minBorrowRate",
|
|
6251
|
+
"docs": [
|
|
6252
|
+
"The min borrow rate for this market when the market regardless of utilization",
|
|
6253
|
+
"1 => 1/200 => .5%",
|
|
6254
|
+
"precision: X/200"
|
|
6255
|
+
],
|
|
6256
|
+
"type": "u8"
|
|
6257
|
+
},
|
|
6243
6258
|
{
|
|
6244
6259
|
"name": "padding",
|
|
6245
6260
|
"type": {
|
|
6246
6261
|
"array": [
|
|
6247
6262
|
"u8",
|
|
6248
|
-
|
|
6263
|
+
47
|
|
6249
6264
|
]
|
|
6250
6265
|
}
|
|
6251
6266
|
}
|
|
@@ -12009,6 +12024,11 @@
|
|
|
12009
12024
|
"code": 6267,
|
|
12010
12025
|
"name": "UnableToParsePullOracleMessage",
|
|
12011
12026
|
"msg": "Unable to parse pull oracle message"
|
|
12027
|
+
},
|
|
12028
|
+
{
|
|
12029
|
+
"code": 6268,
|
|
12030
|
+
"name": "MaxBorrows",
|
|
12031
|
+
"msg": "Can not borow more than max borrows"
|
|
12012
12032
|
}
|
|
12013
12033
|
]
|
|
12014
12034
|
}
|
package/lib/testClient.js
CHANGED
|
@@ -8,12 +8,11 @@ class TestClient extends adminClient_1.AdminClient {
|
|
|
8
8
|
throw new Error('Test client must be polling');
|
|
9
9
|
}
|
|
10
10
|
super(config);
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
this.txHandler.blockhashCommitment = 'recent';
|
|
13
11
|
}
|
|
14
12
|
async sendTransaction(tx, additionalSigners, opts, preSigned) {
|
|
15
13
|
const { txSig, slot } = await super.sendTransaction(tx, additionalSigners, opts, preSigned);
|
|
16
14
|
let lastFetchedSlot = this.accountSubscriber.accountLoader.mostRecentSlot;
|
|
15
|
+
await this.fetchAccounts();
|
|
17
16
|
while (lastFetchedSlot < slot) {
|
|
18
17
|
await this.fetchAccounts();
|
|
19
18
|
lastFetchedSlot = this.accountSubscriber.accountLoader.mostRecentSlot;
|
package/lib/tokenFaucet.d.ts
CHANGED
|
@@ -5,14 +5,16 @@ import { Account } from '@solana/spl-token';
|
|
|
5
5
|
import { ConfirmOptions, Connection, PublicKey, TransactionInstruction, TransactionSignature } from '@solana/web3.js';
|
|
6
6
|
import { BN } from '.';
|
|
7
7
|
import { IWallet } from './types';
|
|
8
|
+
import { BankrunContextWrapper } from './bankrun/bankrunConnection';
|
|
8
9
|
export declare class TokenFaucet {
|
|
10
|
+
context?: BankrunContextWrapper;
|
|
9
11
|
connection: Connection;
|
|
10
12
|
wallet: IWallet;
|
|
11
13
|
program: Program;
|
|
12
14
|
provider: AnchorProvider;
|
|
13
15
|
mint: PublicKey;
|
|
14
16
|
opts?: ConfirmOptions;
|
|
15
|
-
constructor(connection: Connection, wallet: IWallet, programId: PublicKey, mint: PublicKey, opts?: ConfirmOptions);
|
|
17
|
+
constructor(connection: Connection, wallet: IWallet, programId: PublicKey, mint: PublicKey, opts?: ConfirmOptions, context?: BankrunContextWrapper);
|
|
16
18
|
getFaucetConfigPublicKeyAndNonce(): Promise<[
|
|
17
19
|
PublicKey,
|
|
18
20
|
number
|
package/lib/tokenFaucet.js
CHANGED
|
@@ -33,12 +33,15 @@ const spl_token_1 = require("@solana/spl-token");
|
|
|
33
33
|
const web3_js_1 = require("@solana/web3.js");
|
|
34
34
|
const token_faucet_json_1 = __importDefault(require("./idl/token_faucet.json"));
|
|
35
35
|
class TokenFaucet {
|
|
36
|
-
constructor(connection, wallet, programId, mint, opts) {
|
|
36
|
+
constructor(connection, wallet, programId, mint, opts, context) {
|
|
37
37
|
this.connection = connection;
|
|
38
|
+
this.context = context;
|
|
38
39
|
this.wallet = wallet;
|
|
39
40
|
this.opts = opts || anchor_1.AnchorProvider.defaultOptions();
|
|
40
41
|
// @ts-ignore
|
|
41
|
-
const provider = new anchor_1.AnchorProvider(connection
|
|
42
|
+
const provider = new anchor_1.AnchorProvider(context ? context.connection.toConnection() : this.connection,
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
wallet, this.opts);
|
|
42
45
|
this.provider = provider;
|
|
43
46
|
this.program = new anchor_1.Program(token_faucet_json_1.default, programId, provider);
|
|
44
47
|
this.mint = mint;
|
|
@@ -60,7 +63,7 @@ class TokenFaucet {
|
|
|
60
63
|
}
|
|
61
64
|
async initialize() {
|
|
62
65
|
const [faucetConfigPublicKey] = await this.getFaucetConfigPublicKeyAndNonce();
|
|
63
|
-
|
|
66
|
+
const ix = this.program.instruction.initialize({
|
|
64
67
|
accounts: {
|
|
65
68
|
faucetConfig: faucetConfigPublicKey,
|
|
66
69
|
admin: this.wallet.publicKey,
|
|
@@ -70,6 +73,9 @@ class TokenFaucet {
|
|
|
70
73
|
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
71
74
|
},
|
|
72
75
|
});
|
|
76
|
+
const tx = new web3_js_1.Transaction().add(ix);
|
|
77
|
+
const txSig = await this.context.sendTransaction(tx);
|
|
78
|
+
return txSig;
|
|
73
79
|
}
|
|
74
80
|
async fetchState() {
|
|
75
81
|
return await this.program.account.faucetConfig.fetch(await this.getFaucetConfigPublicKey());
|
|
@@ -88,10 +94,28 @@ class TokenFaucet {
|
|
|
88
94
|
async mintToUser(userTokenAccount, amount) {
|
|
89
95
|
const mintIx = await this.mintToUserIx(userTokenAccount, amount);
|
|
90
96
|
const tx = new web3_js_1.Transaction().add(mintIx);
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
if (this.context) {
|
|
98
|
+
return await this.context.sendTransaction(tx);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return await this.program.provider.sendAndConfirm(tx, [], this.opts);
|
|
102
|
+
}
|
|
93
103
|
}
|
|
94
104
|
async transferMintAuthority() {
|
|
105
|
+
if (this.context) {
|
|
106
|
+
const ix = this.program.instruction.transferMintAuthority({
|
|
107
|
+
accounts: {
|
|
108
|
+
faucetConfig: await this.getFaucetConfigPublicKey(),
|
|
109
|
+
mintAccount: this.mint,
|
|
110
|
+
mintAuthority: await this.getMintAuthority(),
|
|
111
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
112
|
+
admin: this.wallet.publicKey,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
const tx = new web3_js_1.Transaction().add(ix);
|
|
116
|
+
const txSig = await this.context.sendTransaction(tx);
|
|
117
|
+
return txSig;
|
|
118
|
+
}
|
|
95
119
|
return await this.program.rpc.transferMintAuthority({
|
|
96
120
|
accounts: {
|
|
97
121
|
faucetConfig: await this.getFaucetConfigPublicKey(),
|
|
@@ -107,7 +131,7 @@ class TokenFaucet {
|
|
|
107
131
|
const [associatedTokenPublicKey, createAssociatedAccountIx, mintToTx] = await this.createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount);
|
|
108
132
|
let associatedTokenAccountExists = false;
|
|
109
133
|
try {
|
|
110
|
-
const assosciatedTokenAccount = await this.connection.getAccountInfo(associatedTokenPublicKey);
|
|
134
|
+
const assosciatedTokenAccount = await this.context.connection.getAccountInfo(associatedTokenPublicKey);
|
|
111
135
|
associatedTokenAccountExists = !!assosciatedTokenAccount;
|
|
112
136
|
}
|
|
113
137
|
catch (e) {
|
|
@@ -118,7 +142,13 @@ class TokenFaucet {
|
|
|
118
142
|
if (!skipAccountCreation)
|
|
119
143
|
tx.add(createAssociatedAccountIx);
|
|
120
144
|
tx.add(mintToTx);
|
|
121
|
-
|
|
145
|
+
let txSig;
|
|
146
|
+
if (this.context) {
|
|
147
|
+
txSig = await this.context.sendTransaction(tx);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
|
|
151
|
+
}
|
|
122
152
|
return [associatedTokenPublicKey, txSig];
|
|
123
153
|
}
|
|
124
154
|
async createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount) {
|
|
@@ -134,6 +164,9 @@ class TokenFaucet {
|
|
|
134
164
|
}
|
|
135
165
|
async getTokenAccountInfo(props) {
|
|
136
166
|
const associatedKey = await this.getAssosciatedMockUSDMintAddress(props);
|
|
167
|
+
if (this.context) {
|
|
168
|
+
return await this.context.connection.getTokenAccount(associatedKey);
|
|
169
|
+
}
|
|
137
170
|
return await (0, spl_token_1.getAccount)(this.connection, associatedKey);
|
|
138
171
|
}
|
|
139
172
|
async subscribeToTokenAccount(props) {
|
|
@@ -141,7 +174,7 @@ class TokenFaucet {
|
|
|
141
174
|
const tokenAccountKey = await this.getAssosciatedMockUSDMintAddress(props);
|
|
142
175
|
props.callback(await this.getTokenAccountInfo(props));
|
|
143
176
|
// Couldn't find a way to do it using anchor framework subscription, someone on serum discord recommended this way
|
|
144
|
-
this.connection.onAccountChange(tokenAccountKey, async (_accountInfo /* accountInfo is a buffer which we don't know how to deserialize */) => {
|
|
177
|
+
this.context.connection.onAccountChange(tokenAccountKey, async (_accountInfo /* accountInfo is a buffer which we don't know how to deserialize */) => {
|
|
145
178
|
props.callback(await this.getTokenAccountInfo(props));
|
|
146
179
|
});
|
|
147
180
|
return true;
|
|
@@ -8,7 +8,8 @@ type TransactionBuildingProps = {
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class TransactionParamProcessor {
|
|
10
10
|
private static getComputeUnitsFromSim;
|
|
11
|
-
static getTxSimComputeUnits(tx: VersionedTransaction, connection: Connection, bufferMultiplier: number
|
|
11
|
+
static getTxSimComputeUnits(tx: VersionedTransaction, connection: Connection, bufferMultiplier: number, // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
|
|
12
|
+
lowerBoundCu?: number): Promise<{
|
|
12
13
|
success: boolean;
|
|
13
14
|
computeUnits: number;
|
|
14
15
|
}>;
|
|
@@ -15,8 +15,8 @@ class TransactionParamProcessor {
|
|
|
15
15
|
}
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
|
18
|
-
static async getTxSimComputeUnits(tx, connection, bufferMultiplier // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
|
|
19
|
-
) {
|
|
18
|
+
static async getTxSimComputeUnits(tx, connection, bufferMultiplier, // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
|
|
19
|
+
lowerBoundCu) {
|
|
20
20
|
var _a, _b, _c;
|
|
21
21
|
try {
|
|
22
22
|
if (TEST_SIMS_ALWAYS_FAIL)
|
|
@@ -29,7 +29,11 @@ class TransactionParamProcessor {
|
|
|
29
29
|
}
|
|
30
30
|
const computeUnits = await this.getComputeUnitsFromSim(simTxResult);
|
|
31
31
|
// Apply the buffer, but round down to the MAX_COMPUTE_UNITS, and round up to the nearest whole number
|
|
32
|
-
|
|
32
|
+
let bufferedComputeUnits = Math.ceil(Math.min(computeUnits * bufferMultiplier, MAX_COMPUTE_UNITS));
|
|
33
|
+
// If a lower bound CU is passed then enforce it
|
|
34
|
+
if (lowerBoundCu) {
|
|
35
|
+
bufferedComputeUnits = Math.max(bufferedComputeUnits, Math.min(lowerBoundCu, MAX_COMPUTE_UNITS));
|
|
36
|
+
}
|
|
33
37
|
return {
|
|
34
38
|
success: true,
|
|
35
39
|
computeUnits: bufferedComputeUnits,
|
package/lib/types.d.ts
CHANGED
|
@@ -1085,6 +1085,7 @@ export type ProcessingTxParams = {
|
|
|
1085
1085
|
computeUnitsBufferMultiplier?: number;
|
|
1086
1086
|
useSimulatedComputeUnitsForCUPriceCalculation?: boolean;
|
|
1087
1087
|
getCUPriceFromComputeUnits?: (computeUnits: number) => number;
|
|
1088
|
+
lowerBoundCu?: number;
|
|
1088
1089
|
};
|
|
1089
1090
|
export type TxParams = BaseTxParams & ProcessingTxParams;
|
|
1090
1091
|
export declare class SwapReduceOnly {
|
package/lib/user.js
CHANGED
|
@@ -27,7 +27,7 @@ class User {
|
|
|
27
27
|
this.driftClient = config.driftClient;
|
|
28
28
|
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
29
29
|
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
30
|
-
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.
|
|
30
|
+
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.connection, config.userAccountPublicKey, config.accountSubscription.accountLoader, this.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(this.driftClient.program.account.user.coder.accounts));
|
|
31
31
|
}
|
|
32
32
|
else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
|
|
33
33
|
this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drift-labs/sdk",
|
|
3
|
-
"version": "2.85.0-beta.
|
|
3
|
+
"version": "2.85.0-beta.10",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"author": "crispheaney",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"@pythnetwork/pyth-solana-receiver": "^0.7.0",
|
|
42
42
|
"@solana/spl-token": "0.3.7",
|
|
43
43
|
"@solana/web3.js": "1.92.3",
|
|
44
|
+
"anchor-bankrun": "^0.3.0",
|
|
44
45
|
"rpc-websockets": "7.5.1",
|
|
46
|
+
"solana-bankrun": "^0.3.0",
|
|
45
47
|
"strict-event-emitter-types": "^2.0.0",
|
|
46
48
|
"uuid": "^8.3.2",
|
|
47
49
|
"zstddec": "^0.1.0"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Commitment,
|
|
1
|
+
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
import { BufferAndSlot } from './types';
|
|
4
4
|
import { promiseTimeout } from '../util/promiseTimeout';
|
|
5
|
+
import { Connection } from '../bankrun/bankrunConnection';
|
|
5
6
|
|
|
6
|
-
type AccountToLoad = {
|
|
7
|
+
export type AccountToLoad = {
|
|
7
8
|
publicKey: PublicKey;
|
|
8
9
|
callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
|
|
9
10
|
};
|
|
@@ -288,14 +288,20 @@ export class PollingDriftClientAccountSubscriber
|
|
|
288
288
|
public async fetch(): Promise<void> {
|
|
289
289
|
await this.accountLoader.load();
|
|
290
290
|
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
291
|
-
const
|
|
291
|
+
const bufferAndSlot = this.accountLoader.getBufferAndSlot(
|
|
292
292
|
accountToPoll.publicKey
|
|
293
293
|
);
|
|
294
|
+
|
|
295
|
+
if (!bufferAndSlot) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const { buffer, slot } = bufferAndSlot;
|
|
300
|
+
|
|
294
301
|
if (buffer) {
|
|
295
302
|
const account = this.program.account[
|
|
296
303
|
accountToPoll.key
|
|
297
304
|
].coder.accounts.decodeUnchecked(capitalize(accountToPoll.key), buffer);
|
|
298
|
-
|
|
299
305
|
if (accountToPoll.mapKey != undefined) {
|
|
300
306
|
this[accountToPoll.key].set(accountToPoll.mapKey, {
|
|
301
307
|
data: account,
|
|
@@ -311,9 +317,16 @@ export class PollingDriftClientAccountSubscriber
|
|
|
311
317
|
}
|
|
312
318
|
|
|
313
319
|
for (const [_, oracleToPoll] of this.oraclesToPoll) {
|
|
314
|
-
const
|
|
320
|
+
const bufferAndSlot = this.accountLoader.getBufferAndSlot(
|
|
315
321
|
oracleToPoll.publicKey
|
|
316
322
|
);
|
|
323
|
+
|
|
324
|
+
if (!bufferAndSlot) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const { buffer, slot } = bufferAndSlot;
|
|
329
|
+
|
|
317
330
|
if (buffer) {
|
|
318
331
|
const oracleClient = this.oracleClientCache.get(
|
|
319
332
|
oracleToPoll.source,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
UserAccountEvents,
|
|
5
5
|
UserAccountSubscriber,
|
|
6
6
|
} from './types';
|
|
7
|
-
import {
|
|
7
|
+
import { Connection } from '../bankrun/bankrunConnection';
|
|
8
8
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
9
9
|
import { EventEmitter } from 'events';
|
|
10
10
|
import { PublicKey } from '@solana/web3.js';
|
|
@@ -13,7 +13,7 @@ import { BulkAccountLoader } from './bulkAccountLoader';
|
|
|
13
13
|
|
|
14
14
|
export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
15
15
|
isSubscribed: boolean;
|
|
16
|
-
|
|
16
|
+
connection: Connection;
|
|
17
17
|
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
18
18
|
userAccountPublicKey: PublicKey;
|
|
19
19
|
|
|
@@ -21,18 +21,22 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
21
21
|
callbackId?: string;
|
|
22
22
|
errorCallbackId?: string;
|
|
23
23
|
|
|
24
|
+
decode: (name, buffer) => UserAccount;
|
|
25
|
+
|
|
24
26
|
user?: DataAndSlot<UserAccount>;
|
|
25
27
|
|
|
26
28
|
public constructor(
|
|
27
|
-
|
|
29
|
+
connection: Connection,
|
|
28
30
|
userAccountPublicKey: PublicKey,
|
|
29
|
-
accountLoader: BulkAccountLoader
|
|
31
|
+
accountLoader: BulkAccountLoader,
|
|
32
|
+
decode: (name, buffer) => UserAccount
|
|
30
33
|
) {
|
|
31
34
|
this.isSubscribed = false;
|
|
32
|
-
this.
|
|
35
|
+
this.connection = connection;
|
|
33
36
|
this.accountLoader = accountLoader;
|
|
34
37
|
this.eventEmitter = new EventEmitter();
|
|
35
38
|
this.userAccountPublicKey = userAccountPublicKey;
|
|
39
|
+
this.decode = decode;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
async subscribe(userAccount?: UserAccount): Promise<boolean> {
|
|
@@ -71,10 +75,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
71
75
|
return;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
const account = this.
|
|
75
|
-
'User',
|
|
76
|
-
buffer
|
|
77
|
-
);
|
|
78
|
+
const account = this.decode('User', buffer);
|
|
78
79
|
this.user = { data: account, slot };
|
|
79
80
|
this.eventEmitter.emit('userAccountUpdate', account);
|
|
80
81
|
this.eventEmitter.emit('update');
|
|
@@ -94,19 +95,19 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
94
95
|
|
|
95
96
|
async fetch(): Promise<void> {
|
|
96
97
|
try {
|
|
97
|
-
const dataAndContext = await this.
|
|
98
|
+
const dataAndContext = await this.connection.getAccountInfoAndContext(
|
|
98
99
|
this.userAccountPublicKey,
|
|
99
100
|
this.accountLoader.commitment
|
|
100
101
|
);
|
|
101
102
|
if (dataAndContext.context.slot > (this.user?.slot ?? 0)) {
|
|
102
103
|
this.user = {
|
|
103
|
-
data: dataAndContext.data
|
|
104
|
+
data: this.decode('User', dataAndContext.value.data),
|
|
104
105
|
slot: dataAndContext.context.slot,
|
|
105
106
|
};
|
|
106
107
|
}
|
|
107
108
|
} catch (e) {
|
|
108
109
|
console.log(
|
|
109
|
-
`PollingUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`
|
|
110
|
+
`PollingUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}-${e.stack}`
|
|
110
111
|
);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AccountToLoad, BulkAccountLoader } from './bulkAccountLoader';
|
|
2
|
+
|
|
3
|
+
export class TestBulkAccountLoader extends BulkAccountLoader {
|
|
4
|
+
async loadChunk(accountsToLoadChunks: AccountToLoad[][]): Promise<void> {
|
|
5
|
+
if (accountsToLoadChunks.length === 0) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const accounts = [];
|
|
10
|
+
for (const accountsToLoadChunk of accountsToLoadChunks) {
|
|
11
|
+
for (const accountToLoad of accountsToLoadChunk) {
|
|
12
|
+
const account = await this.connection.getAccountInfoAndContext(
|
|
13
|
+
accountToLoad.publicKey,
|
|
14
|
+
this.commitment
|
|
15
|
+
);
|
|
16
|
+
accounts.push(account);
|
|
17
|
+
const newSlot = account.context.slot;
|
|
18
|
+
if (newSlot > this.mostRecentSlot) {
|
|
19
|
+
this.mostRecentSlot = newSlot;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (accountToLoad.callbacks.size === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const key = accountToLoad.publicKey.toBase58();
|
|
27
|
+
const prev = this.bufferAndSlotMap.get(key);
|
|
28
|
+
|
|
29
|
+
if (prev && newSlot < prev.slot) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let newBuffer: Buffer | undefined = undefined;
|
|
34
|
+
|
|
35
|
+
if (account.value) {
|
|
36
|
+
newBuffer = account.value.data;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!prev) {
|
|
40
|
+
this.bufferAndSlotMap.set(key, { slot: newSlot, buffer: newBuffer });
|
|
41
|
+
this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const oldBuffer = prev.buffer;
|
|
46
|
+
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
|
|
47
|
+
this.bufferAndSlotMap.set(key, { slot: newSlot, buffer: newBuffer });
|
|
48
|
+
this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|