@drift-labs/sdk 2.25.4 → 2.26.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/examples/phoenix.ts +40 -0
  2. package/lib/accounts/pollingUserAccountSubscriber.d.ts +5 -4
  3. package/lib/accounts/pollingUserAccountSubscriber.js +35 -48
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +4 -4
  5. package/lib/accounts/pollingUserStatsAccountSubscriber.js +30 -47
  6. package/lib/accounts/types.d.ts +2 -1
  7. package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
  8. package/lib/accounts/webSocketAccountSubscriber.js +4 -3
  9. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +1 -0
  10. package/lib/accounts/webSocketUserAccountSubscriber.js +9 -0
  11. package/lib/addresses/pda.d.ts +1 -0
  12. package/lib/addresses/pda.js +8 -1
  13. package/lib/adminClient.d.ts +1 -0
  14. package/lib/adminClient.js +20 -0
  15. package/lib/dlob/DLOBApiClient.d.ts +14 -0
  16. package/lib/dlob/DLOBApiClient.js +34 -0
  17. package/lib/dlob/DLOBSubscriber.d.ts +19 -0
  18. package/lib/dlob/DLOBSubscriber.js +42 -0
  19. package/lib/dlob/types.d.ts +16 -0
  20. package/lib/dlob/types.js +2 -0
  21. package/lib/driftClient.d.ts +13 -10
  22. package/lib/driftClient.js +124 -28
  23. package/lib/examples/loadDlob.js +2 -4
  24. package/lib/idl/drift.json +264 -82
  25. package/lib/index.d.ts +4 -0
  26. package/lib/index.js +4 -0
  27. package/lib/phoenix/phoenixFulfillmentConfigMap.d.ts +10 -0
  28. package/lib/phoenix/phoenixFulfillmentConfigMap.js +17 -0
  29. package/lib/phoenix/phoenixSubscriber.d.ts +34 -0
  30. package/lib/phoenix/phoenixSubscriber.js +79 -0
  31. package/lib/slot/SlotSubscriber.js +3 -0
  32. package/lib/tx/retryTxSender.d.ts +2 -1
  33. package/lib/tx/retryTxSender.js +5 -1
  34. package/lib/tx/types.d.ts +4 -1
  35. package/lib/types.d.ts +11 -0
  36. package/lib/userMap/userMap.d.ts +17 -6
  37. package/lib/userMap/userMap.js +74 -46
  38. package/lib/userMap/userStatsMap.d.ts +6 -3
  39. package/lib/userMap/userStatsMap.js +30 -30
  40. package/package.json +2 -1
  41. package/src/accounts/pollingUserAccountSubscriber.ts +51 -63
  42. package/src/accounts/pollingUserStatsAccountSubscriber.ts +46 -62
  43. package/src/accounts/types.ts +2 -1
  44. package/src/accounts/webSocketAccountSubscriber.ts +4 -3
  45. package/src/accounts/webSocketUserAccountSubscriber.ts +10 -0
  46. package/src/addresses/pda.ts +13 -0
  47. package/src/adminClient.ts +34 -0
  48. package/src/dlob/DLOBApiClient.ts +37 -0
  49. package/src/dlob/DLOBSubscriber.ts +57 -0
  50. package/src/dlob/types.ts +20 -0
  51. package/src/driftClient.ts +216 -59
  52. package/src/examples/loadDlob.ts +2 -4
  53. package/src/idl/drift.json +264 -82
  54. package/src/index.ts +4 -0
  55. package/src/phoenix/phoenixFulfillmentConfigMap.ts +26 -0
  56. package/src/phoenix/phoenixSubscriber.ts +156 -0
  57. package/src/slot/SlotSubscriber.ts +4 -0
  58. package/src/tx/retryTxSender.ts +19 -2
  59. package/src/tx/types.ts +13 -0
  60. package/src/types.ts +12 -0
  61. package/src/userMap/userMap.ts +111 -60
  62. package/src/userMap/userStatsMap.ts +43 -44
  63. package/tests/dlob/helpers.ts +3 -1
  64. package/src/assert/assert.js +0 -9
  65. package/src/token/index.js +0 -38
  66. package/src/util/computeUnits.js +0 -27
  67. package/src/util/getTokenAddress.js +0 -9
  68. package/src/util/promiseTimeout.js +0 -14
  69. package/src/util/tps.js +0 -27
@@ -0,0 +1,40 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { PRICE_PRECISION, PhoenixSubscriber } from '../src';
3
+ import { PROGRAM_ID } from '@ellipsis-labs/phoenix-sdk';
4
+
5
+ export async function listenToBook(): Promise<void> {
6
+ const connection = new Connection('https://api.mainnet-beta.solana.com');
7
+
8
+ const phoenixSubscriber = new PhoenixSubscriber({
9
+ connection,
10
+ programId: PROGRAM_ID,
11
+ marketAddress: new PublicKey(
12
+ '4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg'
13
+ ),
14
+ accountSubscription: {
15
+ type: 'websocket',
16
+ },
17
+ });
18
+
19
+ await phoenixSubscriber.subscribe();
20
+
21
+ for (let i = 0; i < 10; i++) {
22
+ const bid = phoenixSubscriber.getBestBid().toNumber() / PRICE_PRECISION;
23
+ const ask = phoenixSubscriber.getBestAsk().toNumber() / PRICE_PRECISION;
24
+ console.log(`iter ${i}:`, bid.toFixed(3), '@', ask.toFixed(3));
25
+ await new Promise((r) => setTimeout(r, 2000));
26
+ }
27
+
28
+ await phoenixSubscriber.unsubscribe();
29
+ }
30
+
31
+ (async function () {
32
+ try {
33
+ await listenToBook();
34
+ } catch (err) {
35
+ console.log('Error: ', err);
36
+ process.exit(1);
37
+ }
38
+
39
+ process.exit(0);
40
+ })();
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { DataAndSlot, AccountToPoll, UserAccountEvents, UserAccountSubscriber } from './types';
2
+ import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './types';
3
3
  import { Program } from '@coral-xyz/anchor';
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
@@ -12,16 +12,17 @@ export declare class PollingUserAccountSubscriber implements UserAccountSubscrib
12
12
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
13
13
  userAccountPublicKey: PublicKey;
14
14
  accountLoader: BulkAccountLoader;
15
- accountsToPoll: Map<string, AccountToPoll>;
15
+ callbackId?: string;
16
16
  errorCallbackId?: string;
17
17
  user?: DataAndSlot<UserAccount>;
18
18
  constructor(program: Program, userAccountPublicKey: PublicKey, accountLoader: BulkAccountLoader);
19
- subscribe(): Promise<boolean>;
19
+ subscribe(userAccount?: UserAccount): Promise<boolean>;
20
20
  addToAccountLoader(): Promise<void>;
21
21
  fetchIfUnloaded(): Promise<void>;
22
22
  fetch(): Promise<void>;
23
- doAccountsExist(): boolean;
23
+ doesAccountExist(): boolean;
24
24
  unsubscribe(): Promise<void>;
25
25
  assertIsSubscribed(): void;
26
26
  getUserAccountAndSlot(): DataAndSlot<UserAccount>;
27
+ updateData(userAccount: UserAccount, slot: number): void;
27
28
  }
@@ -3,95 +3,75 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PollingUserAccountSubscriber = void 0;
4
4
  const types_1 = require("./types");
5
5
  const events_1 = require("events");
6
- const utils_1 = require("./utils");
7
6
  class PollingUserAccountSubscriber {
8
7
  constructor(program, userAccountPublicKey, accountLoader) {
9
- this.accountsToPoll = new Map();
10
8
  this.isSubscribed = false;
11
9
  this.program = program;
12
10
  this.accountLoader = accountLoader;
13
11
  this.eventEmitter = new events_1.EventEmitter();
14
12
  this.userAccountPublicKey = userAccountPublicKey;
15
13
  }
16
- async subscribe() {
14
+ async subscribe(userAccount) {
17
15
  if (this.isSubscribed) {
18
16
  return true;
19
17
  }
18
+ if (userAccount) {
19
+ this.user = { data: userAccount, slot: undefined };
20
+ }
20
21
  await this.addToAccountLoader();
21
22
  await this.fetchIfUnloaded();
22
- if (this.doAccountsExist()) {
23
+ if (this.doesAccountExist()) {
23
24
  this.eventEmitter.emit('update');
24
25
  }
25
26
  this.isSubscribed = true;
26
27
  return true;
27
28
  }
28
29
  async addToAccountLoader() {
29
- if (this.accountsToPoll.size > 0) {
30
+ if (this.callbackId) {
30
31
  return;
31
32
  }
32
- this.accountsToPoll.set(this.userAccountPublicKey.toString(), {
33
- key: 'user',
34
- publicKey: this.userAccountPublicKey,
35
- eventType: 'userAccountUpdate',
33
+ this.callbackId = await this.accountLoader.addAccount(this.userAccountPublicKey, (buffer, slot) => {
34
+ if (!buffer) {
35
+ return;
36
+ }
37
+ if (this.user && this.user.slot > slot) {
38
+ return;
39
+ }
40
+ const account = this.program.account.user.coder.accounts.decode('User', buffer);
41
+ this.user = { data: account, slot };
42
+ this.eventEmitter.emit('userAccountUpdate', account);
43
+ this.eventEmitter.emit('update');
36
44
  });
37
- for (const [_, accountToPoll] of this.accountsToPoll) {
38
- accountToPoll.callbackId = await this.accountLoader.addAccount(accountToPoll.publicKey, (buffer, slot) => {
39
- if (!buffer) {
40
- return;
41
- }
42
- const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
43
- this[accountToPoll.key] = { data: account, slot };
44
- // @ts-ignore
45
- this.eventEmitter.emit(accountToPoll.eventType, account);
46
- this.eventEmitter.emit('update');
47
- });
48
- }
49
45
  this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
50
46
  this.eventEmitter.emit('error', error);
51
47
  });
52
48
  }
53
49
  async fetchIfUnloaded() {
54
- let shouldFetch = false;
55
- for (const [_, accountToPoll] of this.accountsToPoll) {
56
- if (this[accountToPoll.key] === undefined) {
57
- shouldFetch = true;
58
- break;
59
- }
60
- }
61
- if (shouldFetch) {
50
+ if (this.user === undefined) {
62
51
  await this.fetch();
63
52
  }
64
53
  }
65
54
  async fetch() {
55
+ var _a, _b;
66
56
  await this.accountLoader.load();
67
- for (const [_, accountToPoll] of this.accountsToPoll) {
68
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(accountToPoll.publicKey);
69
- if (buffer) {
70
- const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
71
- this[accountToPoll.key] = { data: account, slot };
72
- }
57
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(this.userAccountPublicKey);
58
+ const currentSlot = (_b = (_a = this.user) === null || _a === void 0 ? void 0 : _a.slot) !== null && _b !== void 0 ? _b : 0;
59
+ if (buffer && slot > currentSlot) {
60
+ const account = this.program.account.user.coder.accounts.decode('User', buffer);
61
+ this.user = { data: account, slot };
73
62
  }
74
63
  }
75
- doAccountsExist() {
76
- let success = true;
77
- for (const [_, accountToPoll] of this.accountsToPoll) {
78
- if (!this[accountToPoll.key]) {
79
- success = false;
80
- break;
81
- }
82
- }
83
- return success;
64
+ doesAccountExist() {
65
+ return this.user !== undefined;
84
66
  }
85
67
  async unsubscribe() {
86
68
  if (!this.isSubscribed) {
87
69
  return;
88
70
  }
89
- for (const [_, accountToPoll] of this.accountsToPoll) {
90
- this.accountLoader.removeAccount(accountToPoll.publicKey, accountToPoll.callbackId);
91
- }
71
+ this.accountLoader.removeAccount(this.userAccountPublicKey, this.callbackId);
72
+ this.callbackId = undefined;
92
73
  this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
93
74
  this.errorCallbackId = undefined;
94
- this.accountsToPoll.clear();
95
75
  this.isSubscribed = false;
96
76
  }
97
77
  assertIsSubscribed() {
@@ -103,5 +83,12 @@ class PollingUserAccountSubscriber {
103
83
  this.assertIsSubscribed();
104
84
  return this.user;
105
85
  }
86
+ updateData(userAccount, slot) {
87
+ if (!this.user || this.user.slot < slot) {
88
+ this.user = { data: userAccount, slot };
89
+ this.eventEmitter.emit('userAccountUpdate', userAccount);
90
+ this.eventEmitter.emit('update');
91
+ }
92
+ }
106
93
  }
107
94
  exports.PollingUserAccountSubscriber = PollingUserAccountSubscriber;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { DataAndSlot, AccountToPoll, UserStatsAccountSubscriber, UserStatsAccountEvents } from './types';
2
+ import { DataAndSlot, UserStatsAccountSubscriber, UserStatsAccountEvents } from './types';
3
3
  import { Program } from '@coral-xyz/anchor';
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
@@ -12,15 +12,15 @@ export declare class PollingUserStatsAccountSubscriber implements UserStatsAccou
12
12
  eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
13
13
  userStatsAccountPublicKey: PublicKey;
14
14
  accountLoader: BulkAccountLoader;
15
- accountsToPoll: Map<string, AccountToPoll>;
15
+ callbackId?: string;
16
16
  errorCallbackId?: string;
17
17
  userStats?: DataAndSlot<UserStatsAccount>;
18
18
  constructor(program: Program, userStatsAccountPublicKey: PublicKey, accountLoader: BulkAccountLoader);
19
- subscribe(): Promise<boolean>;
19
+ subscribe(userStatsAccount?: UserStatsAccount): Promise<boolean>;
20
20
  addToAccountLoader(): Promise<void>;
21
21
  fetchIfUnloaded(): Promise<void>;
22
22
  fetch(): Promise<void>;
23
- doAccountsExist(): boolean;
23
+ doesAccountExist(): boolean;
24
24
  unsubscribe(): Promise<void>;
25
25
  assertIsSubscribed(): void;
26
26
  getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
@@ -3,92 +3,75 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PollingUserStatsAccountSubscriber = void 0;
4
4
  const types_1 = require("./types");
5
5
  const events_1 = require("events");
6
- const utils_1 = require("./utils");
7
6
  class PollingUserStatsAccountSubscriber {
8
7
  constructor(program, userStatsAccountPublicKey, accountLoader) {
9
- this.accountsToPoll = new Map();
10
8
  this.isSubscribed = false;
11
9
  this.program = program;
12
10
  this.accountLoader = accountLoader;
13
11
  this.eventEmitter = new events_1.EventEmitter();
14
12
  this.userStatsAccountPublicKey = userStatsAccountPublicKey;
15
13
  }
16
- async subscribe() {
14
+ async subscribe(userStatsAccount) {
17
15
  if (this.isSubscribed) {
18
16
  return true;
19
17
  }
18
+ if (userStatsAccount) {
19
+ this.userStats = { data: userStatsAccount, slot: undefined };
20
+ }
20
21
  await this.addToAccountLoader();
21
22
  await this.fetchIfUnloaded();
22
- if (this.doAccountsExist()) {
23
+ if (this.doesAccountExist()) {
23
24
  this.eventEmitter.emit('update');
24
25
  }
25
26
  this.isSubscribed = true;
26
27
  return true;
27
28
  }
28
29
  async addToAccountLoader() {
29
- if (this.accountsToPoll.size > 0) {
30
+ if (this.callbackId !== undefined) {
30
31
  return;
31
32
  }
32
- this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
33
- key: 'userStats',
34
- publicKey: this.userStatsAccountPublicKey,
35
- eventType: 'userStatsAccountUpdate',
33
+ this.callbackId = await this.accountLoader.addAccount(this.userStatsAccountPublicKey, (buffer, slot) => {
34
+ if (!buffer) {
35
+ return;
36
+ }
37
+ if (this.userStats && this.userStats.slot > slot) {
38
+ return;
39
+ }
40
+ const account = this.program.account.userStats.coder.accounts.decode('UserStats', buffer);
41
+ this.userStats = { data: account, slot };
42
+ this.eventEmitter.emit('userStatsAccountUpdate', account);
43
+ this.eventEmitter.emit('update');
36
44
  });
37
- for (const [_, accountToPoll] of this.accountsToPoll) {
38
- accountToPoll.callbackId = await this.accountLoader.addAccount(accountToPoll.publicKey, (buffer, slot) => {
39
- if (!buffer) {
40
- return;
41
- }
42
- const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
43
- this[accountToPoll.key] = { data: account, slot };
44
- // @ts-ignore
45
- this.eventEmitter.emit(accountToPoll.eventType, account);
46
- this.eventEmitter.emit('update');
47
- });
48
- }
49
45
  this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
50
46
  this.eventEmitter.emit('error', error);
51
47
  });
52
48
  }
53
49
  async fetchIfUnloaded() {
54
- let shouldFetch = false;
55
- for (const [_, accountToPoll] of this.accountsToPoll) {
56
- if (this[accountToPoll.key] === undefined) {
57
- shouldFetch = true;
58
- break;
59
- }
60
- }
61
- if (shouldFetch) {
50
+ if (this.userStats === undefined) {
62
51
  await this.fetch();
63
52
  }
64
53
  }
65
54
  async fetch() {
55
+ var _a, _b;
66
56
  await this.accountLoader.load();
67
- for (const [_, accountToPoll] of this.accountsToPoll) {
68
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(accountToPoll.publicKey);
69
- if (buffer) {
70
- const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
71
- this[accountToPoll.key] = { data: account, slot };
72
- }
57
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(this.userStatsAccountPublicKey);
58
+ const currentSlot = (_b = (_a = this.userStats) === null || _a === void 0 ? void 0 : _a.slot) !== null && _b !== void 0 ? _b : 0;
59
+ if (buffer && slot > currentSlot) {
60
+ const account = this.program.account.userStats.coder.accounts.decode('UserStats', buffer);
61
+ this.userStats = { data: account, slot };
73
62
  }
74
63
  }
75
- doAccountsExist() {
76
- let success = true;
77
- for (const [_, accountToPoll] of this.accountsToPoll) {
78
- if (!this[accountToPoll.key]) {
79
- success = false;
80
- break;
81
- }
82
- }
83
- return success;
64
+ doesAccountExist() {
65
+ return this.userStats !== undefined;
84
66
  }
85
67
  async unsubscribe() {
86
- for (const [_, accountToPoll] of this.accountsToPoll) {
87
- this.accountLoader.removeAccount(accountToPoll.publicKey, accountToPoll.callbackId);
68
+ if (!this.isSubscribed) {
69
+ return;
88
70
  }
71
+ this.accountLoader.removeAccount(this.userStatsAccountPublicKey, this.callbackId);
72
+ this.callbackId = undefined;
89
73
  this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
90
74
  this.errorCallbackId = undefined;
91
- this.accountsToPoll.clear();
92
75
  this.isSubscribed = false;
93
76
  }
94
77
  assertIsSubscribed() {
@@ -11,7 +11,7 @@ export interface AccountSubscriber<T> {
11
11
  subscribe(onChange: (data: T) => void): Promise<void>;
12
12
  fetch(): Promise<void>;
13
13
  unsubscribe(): Promise<void>;
14
- setData(userAccount: T): void;
14
+ setData(userAccount: T, slot?: number): void;
15
15
  }
16
16
  export declare class NotSubscribedError extends Error {
17
17
  name: string;
@@ -51,6 +51,7 @@ export interface UserAccountSubscriber {
51
51
  isSubscribed: boolean;
52
52
  subscribe(userAccount?: UserAccount): Promise<boolean>;
53
53
  fetch(): Promise<void>;
54
+ updateData(userAccount: UserAccount, slot: number): void;
54
55
  unsubscribe(): Promise<void>;
55
56
  getUserAccountAndSlot(): DataAndSlot<UserAccount>;
56
57
  }
@@ -13,7 +13,7 @@ export declare class WebSocketAccountSubscriber<T> implements AccountSubscriber<
13
13
  listenerId?: number;
14
14
  constructor(accountName: string, program: Program, accountPublicKey: PublicKey, decodeBuffer?: (buffer: Buffer) => T);
15
15
  subscribe(onChange: (data: T) => void): Promise<void>;
16
- setData(data: T): void;
16
+ setData(data: T, slot?: number): void;
17
17
  fetch(): Promise<void>;
18
18
  handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void;
19
19
  decodeBuffer(buffer: Buffer): T;
@@ -21,13 +21,14 @@ class WebSocketAccountSubscriber {
21
21
  this.handleRpcResponse(context, accountInfo);
22
22
  }, this.program.provider.opts.commitment);
23
23
  }
24
- setData(data) {
25
- if (this.dataAndSlot) {
24
+ setData(data, slot) {
25
+ const newSlot = slot || 0;
26
+ if (this.dataAndSlot && this.dataAndSlot.slot > newSlot) {
26
27
  return;
27
28
  }
28
29
  this.dataAndSlot = {
29
30
  data,
30
- slot: undefined,
31
+ slot,
31
32
  };
32
33
  }
33
34
  async fetch() {
@@ -17,4 +17,5 @@ export declare class WebSocketUserAccountSubscriber implements UserAccountSubscr
17
17
  unsubscribe(): Promise<void>;
18
18
  assertIsSubscribed(): void;
19
19
  getUserAccountAndSlot(): DataAndSlot<UserAccount>;
20
+ updateData(userAccount: UserAccount, slot: number): void;
20
21
  }
@@ -46,5 +46,14 @@ class WebSocketUserAccountSubscriber {
46
46
  this.assertIsSubscribed();
47
47
  return this.userDataAccountSubscriber.dataAndSlot;
48
48
  }
49
+ updateData(userAccount, slot) {
50
+ var _a;
51
+ const currentDataSlot = ((_a = this.userDataAccountSubscriber.dataAndSlot) === null || _a === void 0 ? void 0 : _a.slot) || 0;
52
+ if (currentDataSlot < slot) {
53
+ this.userDataAccountSubscriber.setData(userAccount, slot);
54
+ this.eventEmitter.emit('userAccountUpdate', userAccount);
55
+ this.eventEmitter.emit('update');
56
+ }
57
+ }
49
58
  }
50
59
  exports.WebSocketUserAccountSubscriber = WebSocketUserAccountSubscriber;
@@ -15,4 +15,5 @@ export declare function getDriftSignerPublicKey(programId: PublicKey): PublicKey
15
15
  export declare function getSerumOpenOrdersPublicKey(programId: PublicKey, market: PublicKey): PublicKey;
16
16
  export declare function getSerumSignerPublicKey(programId: PublicKey, market: PublicKey, nonce: BN): PublicKey;
17
17
  export declare function getSerumFulfillmentConfigPublicKey(programId: PublicKey, market: PublicKey): PublicKey;
18
+ export declare function getPhoenixFulfillmentConfigPublicKey(programId: PublicKey, market: PublicKey): PublicKey;
18
19
  export declare function getReferrerNamePublicKeySync(programId: PublicKey, nameBuffer: number[]): PublicKey;
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.getReferrerNamePublicKeySync = exports.getSerumFulfillmentConfigPublicKey = exports.getSerumSignerPublicKey = exports.getSerumOpenOrdersPublicKey = exports.getDriftSignerPublicKey = exports.getInsuranceFundStakeAccountPublicKey = exports.getInsuranceFundVaultPublicKey = exports.getSpotMarketVaultPublicKey = exports.getSpotMarketPublicKey = exports.getPerpMarketPublicKey = exports.getUserStatsAccountPublicKey = exports.getUserAccountPublicKeySync = exports.getUserAccountPublicKey = exports.getUserAccountPublicKeyAndNonce = exports.getDriftStateAccountPublicKey = exports.getDriftStateAccountPublicKeyAndNonce = void 0;
26
+ exports.getReferrerNamePublicKeySync = exports.getPhoenixFulfillmentConfigPublicKey = exports.getSerumFulfillmentConfigPublicKey = exports.getSerumSignerPublicKey = exports.getSerumOpenOrdersPublicKey = exports.getDriftSignerPublicKey = exports.getInsuranceFundStakeAccountPublicKey = exports.getInsuranceFundVaultPublicKey = exports.getSpotMarketVaultPublicKey = exports.getSpotMarketPublicKey = exports.getPerpMarketPublicKey = exports.getUserStatsAccountPublicKey = exports.getUserAccountPublicKeySync = exports.getUserAccountPublicKey = exports.getUserAccountPublicKeyAndNonce = exports.getDriftStateAccountPublicKey = exports.getDriftStateAccountPublicKeyAndNonce = void 0;
27
27
  const web3_js_1 = require("@solana/web3.js");
28
28
  const anchor = __importStar(require("@coral-xyz/anchor"));
29
29
  async function getDriftStateAccountPublicKeyAndNonce(programId) {
@@ -119,6 +119,13 @@ function getSerumFulfillmentConfigPublicKey(programId, market) {
119
119
  ], programId)[0];
120
120
  }
121
121
  exports.getSerumFulfillmentConfigPublicKey = getSerumFulfillmentConfigPublicKey;
122
+ function getPhoenixFulfillmentConfigPublicKey(programId, market) {
123
+ return web3_js_1.PublicKey.findProgramAddressSync([
124
+ Buffer.from(anchor.utils.bytes.utf8.encode('phoenix_fulfillment_config')),
125
+ market.toBuffer(),
126
+ ], programId)[0];
127
+ }
128
+ exports.getPhoenixFulfillmentConfigPublicKey = getPhoenixFulfillmentConfigPublicKey;
122
129
  function getReferrerNamePublicKeySync(programId, nameBuffer) {
123
130
  return web3_js_1.PublicKey.findProgramAddressSync([
124
131
  Buffer.from(anchor.utils.bytes.utf8.encode('referrer_name')),
@@ -6,6 +6,7 @@ export declare class AdminClient extends DriftClient {
6
6
  initialize(usdcMint: PublicKey, _adminControlsPrices: boolean): Promise<[TransactionSignature]>;
7
7
  initializeSpotMarket(mint: PublicKey, optimalUtilization: number, optimalRate: number, maxRate: number, oracle: PublicKey, oracleSource: OracleSource, initialAssetWeight: number, maintenanceAssetWeight: number, initialLiabilityWeight: number, maintenanceLiabilityWeight: number, imfFactor?: number, liquidatorFee?: number, activeStatus?: boolean, name?: string): Promise<TransactionSignature>;
8
8
  initializeSerumFulfillmentConfig(marketIndex: number, serumMarket: PublicKey, serumProgram: PublicKey): Promise<TransactionSignature>;
9
+ initializePhoenixFulfillmentConfig(marketIndex: number, phoenixMarket: PublicKey): Promise<TransactionSignature>;
9
10
  initializePerpMarket(marketIndex: number, priceOracle: PublicKey, baseAssetReserve: BN, quoteAssetReserve: BN, periodicity: BN, pegMultiplier?: BN, oracleSource?: OracleSource, marginRatioInitial?: number, marginRatioMaintenance?: number, liquidatorFee?: number, activeStatus?: boolean, name?: string): Promise<TransactionSignature>;
10
11
  deleteInitializedPerpMarket(marketIndex: number): Promise<TransactionSignature>;
11
12
  moveAmmPrice(perpMarketIndex: number, baseAssetReserve: BN, quoteAssetReserve: BN, sqrtK?: BN): Promise<TransactionSignature>;
@@ -36,6 +36,7 @@ const driftClient_1 = require("./driftClient");
36
36
  const numericConstants_1 = require("./constants/numericConstants");
37
37
  const trade_1 = require("./math/trade");
38
38
  const amm_1 = require("./math/amm");
39
+ const phoenix_sdk_1 = require("@ellipsis-labs/phoenix-sdk");
39
40
  class AdminClient extends driftClient_1.DriftClient {
40
41
  async initialize(usdcMint, _adminControlsPrices) {
41
42
  const stateAccountRPCResponse = await this.connection.getParsedAccountInfo(await this.getStatePublicKey());
@@ -107,6 +108,25 @@ class AdminClient extends driftClient_1.DriftClient {
107
108
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
108
109
  return txSig;
109
110
  }
111
+ async initializePhoenixFulfillmentConfig(marketIndex, phoenixMarket) {
112
+ const phoenixFulfillmentConfig = (0, pda_1.getPhoenixFulfillmentConfigPublicKey)(this.program.programId, phoenixMarket);
113
+ const tx = await this.program.transaction.initializePhoenixFulfillmentConfig(marketIndex, {
114
+ accounts: {
115
+ admin: this.wallet.publicKey,
116
+ state: await this.getStatePublicKey(),
117
+ baseSpotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
118
+ quoteSpotMarket: this.getQuoteSpotMarketAccount().pubkey,
119
+ driftSigner: this.getSignerPublicKey(),
120
+ phoenixMarket: phoenixMarket,
121
+ phoenixProgram: phoenix_sdk_1.PROGRAM_ID,
122
+ rent: web3_js_1.SYSVAR_RENT_PUBKEY,
123
+ systemProgram: anchor.web3.SystemProgram.programId,
124
+ phoenixFulfillmentConfig,
125
+ },
126
+ });
127
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
128
+ return txSig;
129
+ }
110
130
  async initializePerpMarket(marketIndex, priceOracle, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier = numericConstants_1.PEG_PRECISION, oracleSource = types_1.OracleSource.PYTH, marginRatioInitial = 2000, marginRatioMaintenance = 500, liquidatorFee = 0, activeStatus = true, name = userName_1.DEFAULT_MARKET_NAME) {
111
131
  const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
112
132
  const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, currentPerpMarketIndex);
@@ -0,0 +1,14 @@
1
+ import { DLOBOrdersCoder } from './DLOBOrders';
2
+ import { DLOB } from './DLOB';
3
+ type DLOBApiClientConfig = {
4
+ url: string;
5
+ };
6
+ export declare class DLOBApiClient {
7
+ url: string;
8
+ dlobCoder: DLOBOrdersCoder;
9
+ lastSeenDLOB: DLOB;
10
+ lastSeenSlot: number;
11
+ constructor(config: DLOBApiClientConfig);
12
+ getDLOB(slot: number): Promise<DLOB>;
13
+ }
14
+ export {};
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DLOBApiClient = void 0;
7
+ const node_fetch_1 = __importDefault(require("node-fetch"));
8
+ const DLOBOrders_1 = require("./DLOBOrders");
9
+ const DLOB_1 = require("./DLOB");
10
+ class DLOBApiClient {
11
+ constructor(config) {
12
+ this.dlobCoder = DLOBOrders_1.DLOBOrdersCoder.create();
13
+ this.lastSeenSlot = 0;
14
+ this.url = config.url;
15
+ }
16
+ async getDLOB(slot) {
17
+ const r = await (0, node_fetch_1.default)(this.url);
18
+ if (!r.ok) {
19
+ throw new Error(`Failed to fetch DLOB from ${this.url}`);
20
+ }
21
+ const resp = await r.json();
22
+ const responseSlot = resp['slot'];
23
+ if (responseSlot > this.lastSeenSlot) {
24
+ const dlobOrdersBuffer = Buffer.from(resp['data'], 'base64');
25
+ const dlobOrders = this.dlobCoder.decode(Buffer.from(dlobOrdersBuffer));
26
+ const dlob = new DLOB_1.DLOB();
27
+ dlob.initFromOrders(dlobOrders, slot);
28
+ this.lastSeenDLOB = dlob;
29
+ this.lastSeenSlot = responseSlot;
30
+ }
31
+ return this.lastSeenDLOB;
32
+ }
33
+ }
34
+ exports.DLOBApiClient = DLOBApiClient;
@@ -0,0 +1,19 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { DLOB } from './DLOB';
4
+ import { EventEmitter } from 'events';
5
+ import StrictEventEmitter from 'strict-event-emitter-types';
6
+ import { DLOBSource, DLOBSubscriberEvents, DLOBSubscriptionConfig, SlotSource } from './types';
7
+ export declare class DLOBSubscriber {
8
+ dlobSource: DLOBSource;
9
+ slotSource: SlotSource;
10
+ updateFrequency: number;
11
+ intervalId?: NodeJS.Timeout;
12
+ dlob: DLOB;
13
+ eventEmitter: StrictEventEmitter<EventEmitter, DLOBSubscriberEvents>;
14
+ constructor(config: DLOBSubscriptionConfig);
15
+ subscribe(): Promise<void>;
16
+ updateDLOB(): Promise<void>;
17
+ getDLOB(): DLOB;
18
+ unsubscribe(): Promise<void>;
19
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DLOBSubscriber = void 0;
4
+ const DLOB_1 = require("./DLOB");
5
+ const events_1 = require("events");
6
+ class DLOBSubscriber {
7
+ constructor(config) {
8
+ this.dlob = new DLOB_1.DLOB();
9
+ this.dlobSource = config.dlobSource;
10
+ this.slotSource = config.slotSource;
11
+ this.updateFrequency = config.updateFrequency;
12
+ this.eventEmitter = new events_1.EventEmitter();
13
+ }
14
+ async subscribe() {
15
+ if (this.intervalId) {
16
+ return;
17
+ }
18
+ await this.updateDLOB();
19
+ this.intervalId = setInterval(async () => {
20
+ try {
21
+ await this.updateDLOB();
22
+ this.eventEmitter.emit('update', this.dlob);
23
+ }
24
+ catch (e) {
25
+ this.eventEmitter.emit('error', e);
26
+ }
27
+ }, this.updateFrequency);
28
+ }
29
+ async updateDLOB() {
30
+ this.dlob = await this.dlobSource.getDLOB(this.slotSource.getSlot());
31
+ }
32
+ getDLOB() {
33
+ return this.dlob;
34
+ }
35
+ async unsubscribe() {
36
+ if (this.intervalId) {
37
+ clearInterval(this.intervalId);
38
+ this.intervalId = undefined;
39
+ }
40
+ }
41
+ }
42
+ exports.DLOBSubscriber = DLOBSubscriber;
@@ -0,0 +1,16 @@
1
+ import { DLOB } from './DLOB';
2
+ export type DLOBSubscriptionConfig = {
3
+ dlobSource: DLOBSource;
4
+ slotSource: SlotSource;
5
+ updateFrequency: number;
6
+ };
7
+ export interface DLOBSubscriberEvents {
8
+ update: (dlob: DLOB) => void;
9
+ error: (e: Error) => void;
10
+ }
11
+ export interface DLOBSource {
12
+ getDLOB(slot: number): Promise<DLOB>;
13
+ }
14
+ export interface SlotSource {
15
+ getSlot(): number;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });