@drift-labs/sdk 2.85.0-beta.3 → 2.85.0-beta.5

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.
@@ -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": "padding1",
6202
- "type": {
6203
- "array": [
6204
- "u8",
6205
- 2
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
- 48
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;
@@ -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
@@ -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, wallet, this.opts);
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
- return await this.program.rpc.initialize({
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
- const txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
92
- return txSig;
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
- const txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
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;
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.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
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",
3
+ "version": "2.85.0-beta.5",
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, Connection, PublicKey } from '@solana/web3.js';
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 { buffer, slot } = this.accountLoader.getBufferAndSlot(
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 { buffer, slot } = this.accountLoader.getBufferAndSlot(
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 { Program } from '@coral-xyz/anchor';
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
- program: Program;
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
- program: Program,
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.program = program;
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.program.account.user.coder.accounts.decode(
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.program.account.user.fetchAndContext(
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 as UserAccount,
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
+ }