@drift-labs/sdk 2.66.0-beta.1 → 2.66.0-beta.3

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 CHANGED
@@ -1 +1 @@
1
- 2.66.0-beta.1
1
+ 2.66.0-beta.3
@@ -2,12 +2,13 @@ import { Commitment, PublicKey } from '@solana/web3.js';
2
2
  import { UserAccount } from '../types';
3
3
  import { BasicUserAccountSubscriber } from './basicUserAccountSubscriber';
4
4
  import { Program } from '@coral-xyz/anchor';
5
+ import { UserAccountSubscriber } from './types';
5
6
  /**
6
7
  * Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
7
8
  * date on subscribe (or call to fetch) if no account data is provided on init.
8
9
  * Expect to use only 1 RPC call unless you call fetch repeatedly.
9
10
  */
10
- export declare class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber {
11
+ export declare class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber implements UserAccountSubscriber {
11
12
  program: Program;
12
13
  commitment: Commitment;
13
14
  constructor(program: Program, userAccountPublicKey: PublicKey, data?: UserAccount, slot?: number, commitment?: Commitment);
@@ -1,9 +1,10 @@
1
+ /// <reference types="node" />
1
2
  import { UserMap } from './userMap';
2
3
  export declare class PollingSubscription {
3
4
  private userMap;
4
5
  private frequency;
5
6
  private skipInitialLoad;
6
- intervalId?: ReturnType<typeof setTimeout>;
7
+ intervalId?: NodeJS.Timeout;
7
8
  constructor({ userMap, frequency, skipInitialLoad, }: {
8
9
  userMap: UserMap;
9
10
  frequency: number;
@@ -8,15 +8,17 @@ class PollingSubscription {
8
8
  this.skipInitialLoad = skipInitialLoad;
9
9
  }
10
10
  async subscribe() {
11
- if (this.intervalId) {
11
+ if (this.intervalId || this.frequency <= 0) {
12
12
  return;
13
13
  }
14
- if (this.frequency > 0) {
15
- this.intervalId = setInterval(this.userMap.sync.bind(this.userMap), this.frequency);
16
- }
14
+ const executeSync = async () => {
15
+ await this.userMap.sync();
16
+ this.intervalId = setTimeout(executeSync, this.frequency);
17
+ };
17
18
  if (!this.skipInitialLoad) {
18
19
  await this.userMap.sync();
19
20
  }
21
+ executeSync();
20
22
  }
21
23
  async unsubscribe() {
22
24
  if (this.intervalId) {
@@ -225,6 +225,7 @@ class UserMap {
225
225
  return userAuthKeys;
226
226
  }
227
227
  async sync() {
228
+ var _a;
228
229
  if (this.syncPromise) {
229
230
  return this.syncPromise;
230
231
  }
@@ -245,43 +246,44 @@ class UserMap {
245
246
  withContext: true,
246
247
  },
247
248
  ];
248
- const rpcJSONResponse =
249
249
  // @ts-ignore
250
- await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
250
+ const rpcJSONResponse = await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
251
251
  const rpcResponseAndContext = rpcJSONResponse.result;
252
252
  const slot = rpcResponseAndContext.context.slot;
253
253
  this.updateLatestSlot(slot);
254
254
  const programAccountBufferMap = new Map();
255
- for (const programAccount of rpcResponseAndContext.value) {
255
+ rpcResponseAndContext.value.forEach((programAccount) => {
256
256
  programAccountBufferMap.set(programAccount.pubkey.toString(),
257
257
  // @ts-ignore
258
258
  buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]));
259
- }
260
- for (const [key, buffer] of programAccountBufferMap.entries()) {
261
- if (!this.has(key)) {
262
- const userAccount = this.decode('User', buffer);
263
- await this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
264
- this.get(key).accountSubscriber.updateData(userAccount, slot);
259
+ });
260
+ const promises = Array.from(programAccountBufferMap.entries()).map(([key, buffer]) => (async () => {
261
+ const currAccountWithSlot = this.getWithSlot(key);
262
+ if (currAccountWithSlot) {
263
+ if (slot >= currAccountWithSlot.slot) {
264
+ const userAccount = this.decode('User', buffer);
265
+ this.updateUserAccount(key, userAccount, slot);
266
+ }
265
267
  }
266
268
  else {
267
269
  const userAccount = this.decode('User', buffer);
268
- this.get(key).accountSubscriber.updateData(userAccount, slot);
270
+ await this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
269
271
  }
270
- // give event loop a chance to breathe
271
- await new Promise((resolve) => setTimeout(resolve, 0));
272
- }
273
- for (const [key, user] of this.entries()) {
272
+ })());
273
+ await Promise.all(promises);
274
+ for (const [key] of this.entries()) {
274
275
  if (!programAccountBufferMap.has(key)) {
275
- await user.unsubscribe();
276
- this.userMap.delete(key);
276
+ const user = this.get(key);
277
+ if (user) {
278
+ await user.unsubscribe();
279
+ this.userMap.delete(key);
280
+ }
277
281
  }
278
- // give event loop a chance to breathe
279
- await new Promise((resolve) => setTimeout(resolve, 0));
280
282
  }
281
283
  }
282
- catch (e) {
283
- console.error(`Error in UserMap.sync():`);
284
- console.error(e);
284
+ catch (err) {
285
+ const e = err;
286
+ console.error(`Error in UserMap.sync(): ${e.message} ${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
285
287
  }
286
288
  finally {
287
289
  this.syncPromiseResolver();
@@ -302,17 +304,19 @@ class UserMap {
302
304
  }
303
305
  }
304
306
  async updateUserAccount(key, userAccount, slot) {
307
+ const userWithSlot = this.getWithSlot(key);
305
308
  this.updateLatestSlot(slot);
306
- if (!this.has(key)) {
307
- this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
309
+ if (userWithSlot) {
310
+ if (slot >= userWithSlot.slot) {
311
+ userWithSlot.data.accountSubscriber.updateData(userAccount, slot);
312
+ this.userMap.set(key, {
313
+ data: userWithSlot.data,
314
+ slot,
315
+ });
316
+ }
308
317
  }
309
318
  else {
310
- const user = this.get(key);
311
- user.accountSubscriber.updateData(userAccount, slot);
312
- this.userMap.set(key, {
313
- data: user,
314
- slot,
315
- });
319
+ this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
316
320
  }
317
321
  }
318
322
  updateLatestSlot(slot) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.66.0-beta.1",
3
+ "version": "2.66.0-beta.3",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -2,13 +2,17 @@ import { Commitment, PublicKey } from '@solana/web3.js';
2
2
  import { UserAccount } from '../types';
3
3
  import { BasicUserAccountSubscriber } from './basicUserAccountSubscriber';
4
4
  import { Program } from '@coral-xyz/anchor';
5
+ import { UserAccountSubscriber } from './types';
5
6
 
6
7
  /**
7
8
  * Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
8
9
  * date on subscribe (or call to fetch) if no account data is provided on init.
9
10
  * Expect to use only 1 RPC call unless you call fetch repeatedly.
10
11
  */
11
- export class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber {
12
+ export class OneShotUserAccountSubscriber
13
+ extends BasicUserAccountSubscriber
14
+ implements UserAccountSubscriber
15
+ {
12
16
  program: Program;
13
17
  commitment: Commitment;
14
18
 
@@ -5,7 +5,7 @@ export class PollingSubscription {
5
5
  private frequency: number;
6
6
  private skipInitialLoad: boolean;
7
7
 
8
- intervalId?: ReturnType<typeof setTimeout>;
8
+ intervalId?: NodeJS.Timeout;
9
9
 
10
10
  constructor({
11
11
  userMap,
@@ -23,20 +23,19 @@ export class PollingSubscription {
23
23
  }
24
24
 
25
25
  public async subscribe(): Promise<void> {
26
- if (this.intervalId) {
26
+ if (this.intervalId || this.frequency <= 0) {
27
27
  return;
28
28
  }
29
29
 
30
- if (this.frequency > 0) {
31
- this.intervalId = setInterval(
32
- this.userMap.sync.bind(this.userMap),
33
- this.frequency
34
- );
35
- }
30
+ const executeSync = async () => {
31
+ await this.userMap.sync();
32
+ this.intervalId = setTimeout(executeSync, this.frequency);
33
+ };
36
34
 
37
35
  if (!this.skipInitialLoad) {
38
36
  await this.userMap.sync();
39
37
  }
38
+ executeSync();
40
39
  }
41
40
 
42
41
  public async unsubscribe(): Promise<void> {
@@ -362,25 +362,20 @@ export class UserMap implements UserMapInterface {
362
362
  },
363
363
  ];
364
364
 
365
- const rpcJSONResponse: any =
366
- // @ts-ignore
367
- await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
368
-
365
+ // @ts-ignore
366
+ const rpcJSONResponse: any = await this.connection._rpcRequest(
367
+ 'getProgramAccounts',
368
+ rpcRequestArgs
369
+ );
369
370
  const rpcResponseAndContext: RpcResponseAndContext<
370
- Array<{
371
- pubkey: PublicKey;
372
- account: {
373
- data: [string, string];
374
- };
375
- }>
371
+ Array<{ pubkey: PublicKey; account: { data: [string, string] } }>
376
372
  > = rpcJSONResponse.result;
377
-
378
373
  const slot = rpcResponseAndContext.context.slot;
379
374
 
380
375
  this.updateLatestSlot(slot);
381
376
 
382
377
  const programAccountBufferMap = new Map<string, Buffer>();
383
- for (const programAccount of rpcResponseAndContext.value) {
378
+ rpcResponseAndContext.value.forEach((programAccount) => {
384
379
  programAccountBufferMap.set(
385
380
  programAccount.pubkey.toString(),
386
381
  // @ts-ignore
@@ -389,32 +384,38 @@ export class UserMap implements UserMapInterface {
389
384
  programAccount.account.data[1]
390
385
  )
391
386
  );
392
- }
387
+ });
393
388
 
394
- for (const [key, buffer] of programAccountBufferMap.entries()) {
395
- if (!this.has(key)) {
396
- const userAccount = this.decode('User', buffer);
397
- await this.addPubkey(new PublicKey(key), userAccount, slot);
398
- this.get(key).accountSubscriber.updateData(userAccount, slot);
399
- } else {
400
- const userAccount = this.decode('User', buffer);
401
- this.get(key).accountSubscriber.updateData(userAccount, slot);
402
- }
403
- // give event loop a chance to breathe
404
- await new Promise((resolve) => setTimeout(resolve, 0));
405
- }
389
+ const promises = Array.from(programAccountBufferMap.entries()).map(
390
+ ([key, buffer]) =>
391
+ (async () => {
392
+ const currAccountWithSlot = this.getWithSlot(key);
393
+ if (currAccountWithSlot) {
394
+ if (slot >= currAccountWithSlot.slot) {
395
+ const userAccount = this.decode('User', buffer);
396
+ this.updateUserAccount(key, userAccount, slot);
397
+ }
398
+ } else {
399
+ const userAccount = this.decode('User', buffer);
400
+ await this.addPubkey(new PublicKey(key), userAccount, slot);
401
+ }
402
+ })()
403
+ );
406
404
 
407
- for (const [key, user] of this.entries()) {
405
+ await Promise.all(promises);
406
+
407
+ for (const [key] of this.entries()) {
408
408
  if (!programAccountBufferMap.has(key)) {
409
- await user.unsubscribe();
410
- this.userMap.delete(key);
409
+ const user = this.get(key);
410
+ if (user) {
411
+ await user.unsubscribe();
412
+ this.userMap.delete(key);
413
+ }
411
414
  }
412
- // give event loop a chance to breathe
413
- await new Promise((resolve) => setTimeout(resolve, 0));
414
415
  }
415
- } catch (e) {
416
- console.error(`Error in UserMap.sync():`);
417
- console.error(e);
416
+ } catch (err) {
417
+ const e = err as Error;
418
+ console.error(`Error in UserMap.sync(): ${e.message} ${e.stack ?? ''}`);
418
419
  } finally {
419
420
  this.syncPromiseResolver();
420
421
  this.syncPromise = undefined;
@@ -446,16 +447,18 @@ export class UserMap implements UserMapInterface {
446
447
  userAccount: UserAccount,
447
448
  slot: number
448
449
  ) {
450
+ const userWithSlot = this.getWithSlot(key);
449
451
  this.updateLatestSlot(slot);
450
- if (!this.has(key)) {
451
- this.addPubkey(new PublicKey(key), userAccount, slot);
452
+ if (userWithSlot) {
453
+ if (slot >= userWithSlot.slot) {
454
+ userWithSlot.data.accountSubscriber.updateData(userAccount, slot);
455
+ this.userMap.set(key, {
456
+ data: userWithSlot.data,
457
+ slot,
458
+ });
459
+ }
452
460
  } else {
453
- const user = this.get(key);
454
- user.accountSubscriber.updateData(userAccount, slot);
455
- this.userMap.set(key, {
456
- data: user,
457
- slot,
458
- });
461
+ this.addPubkey(new PublicKey(key), userAccount, slot);
459
462
  }
460
463
  }
461
464
 
package/tests/amm/test.ts CHANGED
@@ -615,11 +615,11 @@ describe('AMM Tests', () => {
615
615
  assert(termsSuiExample.effectiveLeverageCapped <= 1.000001);
616
616
  assert(termsSuiExample.inventorySpreadScale == 1.00007);
617
617
  assert(
618
- termsSuiExample.longSpread == 259073,
618
+ termsSuiExample.longSpread == 269818,
619
619
  `SUI long spread got ${termsSuiExample.longSpread}`
620
620
  );
621
621
  assert(
622
- termsSuiExample.shortSpread == 3712,
622
+ termsSuiExample.shortSpread == 3920,
623
623
  `SUI short spread got ${termsSuiExample.shortSpread}`
624
624
  );
625
625
 
@@ -680,7 +680,26 @@ describe('AMM Tests', () => {
680
680
  );
681
681
 
682
682
  console.log(termsSuiExampleMod2);
683
- // assert(_.isEqual(termsSuiExampleMod2, termsSuiExampleMod1));
683
+ assert(
684
+ _.isEqual(
685
+ termsSuiExampleMod2.maxTargetSpread,
686
+ termsSuiExampleMod1.maxTargetSpread
687
+ )
688
+ );
689
+ assert(
690
+ _.isEqual(
691
+ termsSuiExampleMod2.shortSpreadwPS,
692
+ termsSuiExampleMod1.shortSpreadwPS
693
+ )
694
+ );
695
+ assert(
696
+ _.isEqual(
697
+ termsSuiExampleMod2.longSpreadwPS,
698
+ termsSuiExampleMod1.longSpreadwPS
699
+ )
700
+ );
701
+
702
+ // note: effectiveLeverage as currently implemented is sensitive to peg change
684
703
  });
685
704
 
686
705
  it('Spread Reserves (with offset)', () => {