@drift-labs/sdk 0.2.0-master.39 → 0.2.0-master.40

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.
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Commitment, Connection, PublicKey } from '@solana/web3.js';
3
3
  import { BufferAndSlot } from './types';
4
+ import { Mutex } from 'async-mutex';
4
5
  declare type AccountToLoad = {
5
6
  publicKey: PublicKey;
6
7
  callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
@@ -14,6 +15,7 @@ export declare class BulkAccountLoader {
14
15
  errorCallbacks: Map<string, (e: any) => void>;
15
16
  intervalId?: NodeJS.Timer;
16
17
  loadPromise?: Promise<void>;
18
+ loadPromiseLock: Mutex;
17
19
  loadPromiseResolver: () => void;
18
20
  lastTimeLoadingPromiseCleared: number;
19
21
  mostRecentSlot: number;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BulkAccountLoader = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const promiseTimeout_1 = require("../util/promiseTimeout");
6
+ const async_mutex_1 = require("async-mutex");
6
7
  const GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE = 99;
7
8
  const oneMinute = 60 * 1000;
8
9
  class BulkAccountLoader {
@@ -10,6 +11,7 @@ class BulkAccountLoader {
10
11
  this.accountsToLoad = new Map();
11
12
  this.bufferAndSlotMap = new Map();
12
13
  this.errorCallbacks = new Map();
14
+ this.loadPromiseLock = new async_mutex_1.Mutex();
13
15
  this.lastTimeLoadingPromiseCleared = Date.now();
14
16
  this.mostRecentSlot = 0;
15
17
  this.connection = connection;
@@ -36,7 +38,9 @@ class BulkAccountLoader {
36
38
  this.startPolling();
37
39
  }
38
40
  // if a new account needs to be polled, remove the cached loadPromise in case client calls load immediately after
39
- this.loadPromise = undefined;
41
+ this.loadPromiseLock.runExclusive(() => {
42
+ this.loadPromise = undefined;
43
+ });
40
44
  return callbackId;
41
45
  }
42
46
  removeAccount(publicKey, callbackId) {
@@ -66,36 +70,38 @@ class BulkAccountLoader {
66
70
  .map((begin) => array.slice(begin, begin + size));
67
71
  }
68
72
  async load() {
69
- if (this.loadPromise) {
70
- const now = Date.now();
71
- if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
72
- this.loadPromise = undefined;
73
+ await this.loadPromiseLock.runExclusive(async () => {
74
+ if (this.loadPromise) {
75
+ const now = Date.now();
76
+ if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
77
+ this.loadPromise = undefined;
78
+ }
79
+ else {
80
+ return this.loadPromise;
81
+ }
73
82
  }
74
- else {
75
- return this.loadPromise;
83
+ this.loadPromise = new Promise((resolver) => {
84
+ this.loadPromiseResolver = resolver;
85
+ });
86
+ this.lastTimeLoadingPromiseCleared = Date.now();
87
+ try {
88
+ const chunks = this.chunks(Array.from(this.accountsToLoad.values()), GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE);
89
+ await Promise.all(chunks.map((chunk) => {
90
+ return this.loadChunk(chunk);
91
+ }));
76
92
  }
77
- }
78
- this.loadPromise = new Promise((resolver) => {
79
- this.loadPromiseResolver = resolver;
80
- });
81
- this.lastTimeLoadingPromiseCleared = Date.now();
82
- try {
83
- const chunks = this.chunks(Array.from(this.accountsToLoad.values()), GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE);
84
- await Promise.all(chunks.map((chunk) => {
85
- return this.loadChunk(chunk);
86
- }));
87
- }
88
- catch (e) {
89
- console.error(`Error in bulkAccountLoader.load()`);
90
- console.error(e);
91
- for (const [_, callback] of this.errorCallbacks) {
92
- callback(e);
93
+ catch (e) {
94
+ console.error(`Error in bulkAccountLoader.load()`);
95
+ console.error(e);
96
+ for (const [_, callback] of this.errorCallbacks) {
97
+ callback(e);
98
+ }
93
99
  }
94
- }
95
- finally {
96
- this.loadPromiseResolver();
97
- this.loadPromise = undefined;
98
- }
100
+ finally {
101
+ this.loadPromiseResolver();
102
+ this.loadPromise = undefined;
103
+ }
104
+ });
99
105
  }
100
106
  async loadChunk(accountsToLoad) {
101
107
  if (accountsToLoad.length === 0) {
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
2
  import { SpotMarketAccount, PerpMarketAccount, OracleSource, StateAccount, UserAccount, UserStatsAccount } from '../types';
4
3
  import StrictEventEmitter from 'strict-event-emitter-types';
5
4
  import { EventEmitter } from 'events';
@@ -127,9 +127,9 @@ class DriftClient {
127
127
  });
128
128
  }
129
129
  async subscribe() {
130
- const subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
130
+ let subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
131
131
  if (this.userStats !== undefined) {
132
- subscribePromises.concat(this.userStats.subscribe());
132
+ subscribePromises = subscribePromises.concat(this.userStats.subscribe());
133
133
  }
134
134
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce((success, prevSuccess) => success && prevSuccess);
135
135
  return this.isSubscribed;
@@ -141,18 +141,18 @@ class DriftClient {
141
141
  * Forces the accountSubscriber to fetch account updates from rpc
142
142
  */
143
143
  async fetchAccounts() {
144
- const promises = [...this.users.values()]
144
+ let promises = [...this.users.values()]
145
145
  .map((user) => user.fetchAccounts())
146
146
  .concat(this.accountSubscriber.fetch());
147
147
  if (this.userStats) {
148
- promises.concat(this.userStats.fetchAccounts());
148
+ promises = promises.concat(this.userStats.fetchAccounts());
149
149
  }
150
150
  await Promise.all(promises);
151
151
  }
152
152
  async unsubscribe() {
153
- const unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
153
+ let unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
154
154
  if (this.userStats !== undefined) {
155
- unsubscribePromises.concat(this.userStats.unsubscribe());
155
+ unsubscribePromises = unsubscribePromises.concat(this.userStats.unsubscribe());
156
156
  }
157
157
  await Promise.all(unsubscribePromises);
158
158
  this.isSubscribed = false;
@@ -221,11 +221,22 @@ class DriftClient {
221
221
  this.authority = newWallet.publicKey;
222
222
  if (this.isSubscribed) {
223
223
  await Promise.all(this.unsubscribeUsers());
224
+ if (this.userStats) {
225
+ await this.userStats.unsubscribe();
226
+ this.userStats = new userStats_1.UserStats({
227
+ driftClient: this,
228
+ userStatsAccountPublicKey: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.authority),
229
+ accountSubscription: this.userAccountSubscriptionConfig,
230
+ });
231
+ }
224
232
  }
225
233
  this.users.clear();
226
234
  this.createUsers(subAccountIds, this.userAccountSubscriptionConfig);
227
235
  if (this.isSubscribed) {
228
236
  await Promise.all(this.subscribeUsers());
237
+ if (this.userStats) {
238
+ await this.userStats.subscribe();
239
+ }
229
240
  }
230
241
  this.activeSubAccountId = activeSubAccountId;
231
242
  this.userStatsAccountPublicKey = undefined;
@@ -245,8 +256,9 @@ class DriftClient {
245
256
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
246
257
  const tx = new web3_js_1.Transaction();
247
258
  if (subAccountId === 0) {
248
- // not the safest assumption, can explicitly check if user stats account exists if it causes problems
249
- tx.add(await this.getInitializeUserStatsIx());
259
+ if (!(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))) {
260
+ tx.add(await this.getInitializeUserStatsIx());
261
+ }
250
262
  }
251
263
  tx.add(initializeUserAccountIx);
252
264
  const { txSig } = await this.txSender.send(tx, [], this.opts);
@@ -706,7 +718,9 @@ class DriftClient {
706
718
  ? await this.getTransferDepositIx(amount, marketIndex, fromSubAccountId, subAccountId)
707
719
  : await this.getDepositInstruction(amount, marketIndex, userTokenAccount, subAccountId, false, false);
708
720
  if (subAccountId === 0) {
709
- tx.add(await this.getInitializeUserStatsIx());
721
+ if (!(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))) {
722
+ tx.add(await this.getInitializeUserStatsIx());
723
+ }
710
724
  }
711
725
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
712
726
  // Close the wrapped sol account at the end of the transaction
@@ -723,7 +737,9 @@ class DriftClient {
723
737
  const depositCollateralIx = await this.getDepositInstruction(amount, marketIndex, associateTokenPublicKey, subAccountId, false, false);
724
738
  const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToIx);
725
739
  if (subAccountId === 0) {
726
- tx.add(await this.getInitializeUserStatsIx());
740
+ if (!(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))) {
741
+ tx.add(await this.getInitializeUserStatsIx());
742
+ }
727
743
  }
728
744
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
729
745
  const txSig = await this.program.provider.sendAndConfirm(tx, []);
package/lib/types.d.ts CHANGED
@@ -449,6 +449,7 @@ export declare type SpotBankruptcyRecord = {
449
449
  marketIndex: number;
450
450
  borrowAmount: BN;
451
451
  cumulativeDepositInterestDelta: BN;
452
+ ifPayment: BN;
452
453
  };
453
454
  export declare type SettlePnlRecord = {
454
455
  ts: BN;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.2.0-master.39",
3
+ "version": "0.2.0-master.40",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -33,12 +33,13 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@project-serum/serum": "^0.13.38",
37
36
  "@project-serum/anchor": "0.25.0-beta.1",
37
+ "@project-serum/serum": "^0.13.38",
38
38
  "@pythnetwork/client": "2.5.3",
39
39
  "@solana/spl-token": "^0.1.6",
40
40
  "@solana/web3.js": "1.41.0",
41
41
  "@switchboard-xyz/switchboard-v2": "^0.0.67",
42
+ "async-mutex": "^0.4.0",
42
43
  "strict-event-emitter-types": "^2.0.0",
43
44
  "uuid": "^8.3.2"
44
45
  },
@@ -53,8 +54,8 @@
53
54
  "eslint-config-prettier": "^8.3.0",
54
55
  "eslint-plugin-prettier": "^3.4.0",
55
56
  "mocha": "^10.0.0",
56
- "ts-node": "^10.8.0",
57
- "prettier": "^2.4.1"
57
+ "prettier": "^2.4.1",
58
+ "ts-node": "^10.8.0"
58
59
  },
59
60
  "description": "SDK for Drift Protocol v1",
60
61
  "engines": {
@@ -2,6 +2,7 @@ import { Commitment, Connection, 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 { Mutex } from 'async-mutex';
5
6
 
6
7
  type AccountToLoad = {
7
8
  publicKey: PublicKey;
@@ -22,6 +23,7 @@ export class BulkAccountLoader {
22
23
  intervalId?: NodeJS.Timer;
23
24
  // to handle clients spamming load
24
25
  loadPromise?: Promise<void>;
26
+ loadPromiseLock: Mutex = new Mutex();
25
27
  loadPromiseResolver: () => void;
26
28
  lastTimeLoadingPromiseCleared = Date.now();
27
29
  mostRecentSlot = 0;
@@ -64,7 +66,9 @@ export class BulkAccountLoader {
64
66
  }
65
67
 
66
68
  // if a new account needs to be polled, remove the cached loadPromise in case client calls load immediately after
67
- this.loadPromise = undefined;
69
+ this.loadPromiseLock.runExclusive(() => {
70
+ this.loadPromise = undefined;
71
+ });
68
72
 
69
73
  return callbackId;
70
74
  }
@@ -101,41 +105,43 @@ export class BulkAccountLoader {
101
105
  }
102
106
 
103
107
  public async load(): Promise<void> {
104
- if (this.loadPromise) {
105
- const now = Date.now();
106
- if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
107
- this.loadPromise = undefined;
108
- } else {
109
- return this.loadPromise;
108
+ await this.loadPromiseLock.runExclusive(async () => {
109
+ if (this.loadPromise) {
110
+ const now = Date.now();
111
+ if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
112
+ this.loadPromise = undefined;
113
+ } else {
114
+ return this.loadPromise;
115
+ }
110
116
  }
111
- }
112
117
 
113
- this.loadPromise = new Promise((resolver) => {
114
- this.loadPromiseResolver = resolver;
115
- });
116
- this.lastTimeLoadingPromiseCleared = Date.now();
117
-
118
- try {
119
- const chunks = this.chunks(
120
- Array.from(this.accountsToLoad.values()),
121
- GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
122
- );
123
-
124
- await Promise.all(
125
- chunks.map((chunk) => {
126
- return this.loadChunk(chunk);
127
- })
128
- );
129
- } catch (e) {
130
- console.error(`Error in bulkAccountLoader.load()`);
131
- console.error(e);
132
- for (const [_, callback] of this.errorCallbacks) {
133
- callback(e);
118
+ this.loadPromise = new Promise((resolver) => {
119
+ this.loadPromiseResolver = resolver;
120
+ });
121
+ this.lastTimeLoadingPromiseCleared = Date.now();
122
+
123
+ try {
124
+ const chunks = this.chunks(
125
+ Array.from(this.accountsToLoad.values()),
126
+ GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
127
+ );
128
+
129
+ await Promise.all(
130
+ chunks.map((chunk) => {
131
+ return this.loadChunk(chunk);
132
+ })
133
+ );
134
+ } catch (e) {
135
+ console.error(`Error in bulkAccountLoader.load()`);
136
+ console.error(e);
137
+ for (const [_, callback] of this.errorCallbacks) {
138
+ callback(e);
139
+ }
140
+ } finally {
141
+ this.loadPromiseResolver();
142
+ this.loadPromise = undefined;
134
143
  }
135
- } finally {
136
- this.loadPromiseResolver();
137
- this.loadPromise = undefined;
138
- }
144
+ });
139
145
  }
140
146
 
141
147
  async loadChunk(accountsToLoad: AccountToLoad[]): Promise<void> {
@@ -230,11 +230,11 @@ export class DriftClient {
230
230
  }
231
231
 
232
232
  public async subscribe(): Promise<boolean> {
233
- const subscribePromises = this.subscribeUsers().concat(
233
+ let subscribePromises = this.subscribeUsers().concat(
234
234
  this.accountSubscriber.subscribe()
235
235
  );
236
236
  if (this.userStats !== undefined) {
237
- subscribePromises.concat(this.userStats.subscribe());
237
+ subscribePromises = subscribePromises.concat(this.userStats.subscribe());
238
238
  }
239
239
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
240
240
  (success, prevSuccess) => success && prevSuccess
@@ -250,21 +250,23 @@ export class DriftClient {
250
250
  * Forces the accountSubscriber to fetch account updates from rpc
251
251
  */
252
252
  public async fetchAccounts(): Promise<void> {
253
- const promises = [...this.users.values()]
253
+ let promises = [...this.users.values()]
254
254
  .map((user) => user.fetchAccounts())
255
255
  .concat(this.accountSubscriber.fetch());
256
256
  if (this.userStats) {
257
- promises.concat(this.userStats.fetchAccounts());
257
+ promises = promises.concat(this.userStats.fetchAccounts());
258
258
  }
259
259
  await Promise.all(promises);
260
260
  }
261
261
 
262
262
  public async unsubscribe(): Promise<void> {
263
- const unsubscribePromises = this.unsubscribeUsers().concat(
263
+ let unsubscribePromises = this.unsubscribeUsers().concat(
264
264
  this.accountSubscriber.unsubscribe()
265
265
  );
266
266
  if (this.userStats !== undefined) {
267
- unsubscribePromises.concat(this.userStats.unsubscribe());
267
+ unsubscribePromises = unsubscribePromises.concat(
268
+ this.userStats.unsubscribe()
269
+ );
268
270
  }
269
271
  await Promise.all(unsubscribePromises);
270
272
  this.isSubscribed = false;
@@ -378,11 +380,28 @@ export class DriftClient {
378
380
 
379
381
  if (this.isSubscribed) {
380
382
  await Promise.all(this.unsubscribeUsers());
383
+
384
+ if (this.userStats) {
385
+ await this.userStats.unsubscribe();
386
+
387
+ this.userStats = new UserStats({
388
+ driftClient: this,
389
+ userStatsAccountPublicKey: getUserStatsAccountPublicKey(
390
+ this.program.programId,
391
+ this.authority
392
+ ),
393
+ accountSubscription: this.userAccountSubscriptionConfig,
394
+ });
395
+ }
381
396
  }
382
397
  this.users.clear();
383
398
  this.createUsers(subAccountIds, this.userAccountSubscriptionConfig);
384
399
  if (this.isSubscribed) {
385
400
  await Promise.all(this.subscribeUsers());
401
+
402
+ if (this.userStats) {
403
+ await this.userStats.subscribe();
404
+ }
386
405
  }
387
406
 
388
407
  this.activeSubAccountId = activeSubAccountId;
@@ -420,8 +439,11 @@ export class DriftClient {
420
439
 
421
440
  const tx = new Transaction();
422
441
  if (subAccountId === 0) {
423
- // not the safest assumption, can explicitly check if user stats account exists if it causes problems
424
- tx.add(await this.getInitializeUserStatsIx());
442
+ if (
443
+ !(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))
444
+ ) {
445
+ tx.add(await this.getInitializeUserStatsIx());
446
+ }
425
447
  }
426
448
  tx.add(initializeUserAccountIx);
427
449
  const { txSig } = await this.txSender.send(tx, [], this.opts);
@@ -1143,7 +1165,11 @@ export class DriftClient {
1143
1165
  );
1144
1166
 
1145
1167
  if (subAccountId === 0) {
1146
- tx.add(await this.getInitializeUserStatsIx());
1168
+ if (
1169
+ !(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))
1170
+ ) {
1171
+ tx.add(await this.getInitializeUserStatsIx());
1172
+ }
1147
1173
  }
1148
1174
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
1149
1175
 
@@ -1202,7 +1228,11 @@ export class DriftClient {
1202
1228
  const tx = new Transaction().add(createAssociatedAccountIx).add(mintToIx);
1203
1229
 
1204
1230
  if (subAccountId === 0) {
1205
- tx.add(await this.getInitializeUserStatsIx());
1231
+ if (
1232
+ !(await this.checkIfAccountExists(this.getUserStatsAccountPublicKey()))
1233
+ ) {
1234
+ tx.add(await this.getInitializeUserStatsIx());
1235
+ }
1206
1236
  }
1207
1237
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
1208
1238
 
package/src/types.ts CHANGED
@@ -371,6 +371,7 @@ export type SpotBankruptcyRecord = {
371
371
  marketIndex: number;
372
372
  borrowAmount: BN;
373
373
  cumulativeDepositInterestDelta: BN;
374
+ ifPayment: BN;
374
375
  };
375
376
 
376
377
  export type SettlePnlRecord = {
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assert = void 0;
4
- function assert(condition, error) {
5
- if (!condition) {
6
- throw new Error(error || 'Unspecified AssertionError');
7
- }
8
- }
9
- exports.assert = assert;
@@ -1,77 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EventList = void 0;
4
- class Node {
5
- constructor(event, next, prev) {
6
- this.event = event;
7
- this.next = next;
8
- this.prev = prev;
9
- }
10
- }
11
- class EventList {
12
- constructor(eventType, maxSize, sortFn, orderDirection) {
13
- this.eventType = eventType;
14
- this.maxSize = maxSize;
15
- this.sortFn = sortFn;
16
- this.orderDirection = orderDirection;
17
- this.size = 0;
18
- }
19
- insert(event) {
20
- this.size++;
21
- const newNode = new Node(event);
22
- if (this.head === undefined) {
23
- this.head = this.tail = newNode;
24
- return;
25
- }
26
- if (this.sortFn(this.head.event, newNode.event) ===
27
- (this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
28
- this.head.prev = newNode;
29
- newNode.next = this.head;
30
- this.head = newNode;
31
- }
32
- else {
33
- let currentNode = this.head;
34
- while (currentNode.next !== undefined &&
35
- this.sortFn(currentNode.next.event, newNode.event) !==
36
- (this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
37
- currentNode = currentNode.next;
38
- }
39
- newNode.next = currentNode.next;
40
- if (currentNode.next !== undefined) {
41
- newNode.next.prev = newNode;
42
- }
43
- currentNode.next = newNode;
44
- newNode.prev = currentNode;
45
- }
46
- if (this.size > this.maxSize) {
47
- this.detach();
48
- }
49
- }
50
- detach() {
51
- const node = this.tail;
52
- if (node.prev !== undefined) {
53
- node.prev.next = node.next;
54
- }
55
- else {
56
- this.head = node.next;
57
- }
58
- if (node.next !== undefined) {
59
- node.next.prev = node.prev;
60
- }
61
- else {
62
- this.tail = node.prev;
63
- }
64
- this.size--;
65
- }
66
- toArray() {
67
- return Array.from(this);
68
- }
69
- *[Symbol.iterator]() {
70
- let node = this.head;
71
- while (node) {
72
- yield node.event;
73
- node = node.next;
74
- }
75
- }
76
- }
77
- exports.EventList = EventList;
@@ -1,157 +0,0 @@
1
- 'use strict';
2
- var __awaiter =
3
- (this && this.__awaiter) ||
4
- function (thisArg, _arguments, P, generator) {
5
- function adopt(value) {
6
- return value instanceof P
7
- ? value
8
- : new P(function (resolve) {
9
- resolve(value);
10
- });
11
- }
12
- return new (P || (P = Promise))(function (resolve, reject) {
13
- function fulfilled(value) {
14
- try {
15
- step(generator.next(value));
16
- } catch (e) {
17
- reject(e);
18
- }
19
- }
20
- function rejected(value) {
21
- try {
22
- step(generator['throw'](value));
23
- } catch (e) {
24
- reject(e);
25
- }
26
- }
27
- function step(result) {
28
- result.done
29
- ? resolve(result.value)
30
- : adopt(result.value).then(fulfilled, rejected);
31
- }
32
- step((generator = generator.apply(thisArg, _arguments || [])).next());
33
- });
34
- };
35
- Object.defineProperty(exports, '__esModule', { value: true });
36
- exports.getTokenAddress = void 0;
37
- const anchor_1 = require('@project-serum/anchor');
38
- const __1 = require('..');
39
- const spl_token_1 = require('@solana/spl-token');
40
- const web3_js_1 = require('@solana/web3.js');
41
- const __2 = require('..');
42
- const banks_1 = require('../constants/spotMarkets');
43
- const getTokenAddress = (mintAddress, userPubKey) => {
44
- return spl_token_1.Token.getAssociatedTokenAddress(
45
- new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`),
46
- spl_token_1.TOKEN_PROGRAM_ID,
47
- new web3_js_1.PublicKey(mintAddress),
48
- new web3_js_1.PublicKey(userPubKey)
49
- );
50
- };
51
- exports.getTokenAddress = getTokenAddress;
52
- const main = () =>
53
- __awaiter(void 0, void 0, void 0, function* () {
54
- // Initialize Drift SDK
55
- const sdkConfig = __2.initialize({ env: 'devnet' });
56
- // Set up the Wallet and Provider
57
- const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
58
- const keypair = web3_js_1.Keypair.fromSecretKey(
59
- Uint8Array.from(JSON.parse(privateKey))
60
- );
61
- const wallet = new __1.Wallet(keypair);
62
- // Set up the Connection
63
- const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
64
- const connection = new web3_js_1.Connection(rpcAddress);
65
- // Set up the Provider
66
- const provider = new anchor_1.AnchorProvider(
67
- connection,
68
- wallet,
69
- anchor_1.AnchorProvider.defaultOptions()
70
- );
71
- // Check SOL Balance
72
- const lamportsBalance = yield connection.getBalance(wallet.publicKey);
73
- console.log('SOL balance:', lamportsBalance / Math.pow(10, 9));
74
- // Misc. other things to set up
75
- const usdcTokenAddress = yield exports.getTokenAddress(
76
- sdkConfig.USDC_MINT_ADDRESS,
77
- wallet.publicKey.toString()
78
- );
79
- // Set up the Drift Clearing House
80
- const clearingHousePublicKey = new web3_js_1.PublicKey(
81
- sdkConfig.CLEARING_HOUSE_PROGRAM_ID
82
- );
83
- const clearingHouse = new __2.ClearingHouse({
84
- connection,
85
- wallet: provider.wallet,
86
- programID: clearingHousePublicKey,
87
- });
88
- yield clearingHouse.subscribe();
89
- // Set up Clearing House user client
90
- const user = new __2.ClearingHouseUser({
91
- clearingHouse,
92
- userAccountPublicKey: yield clearingHouse.getUserAccountPublicKey(),
93
- });
94
- //// Check if clearing house account exists for the current wallet
95
- const userAccountExists = yield user.exists();
96
- if (!userAccountExists) {
97
- //// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
98
- const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
99
- yield clearingHouse.initializeUserAccountAndDepositCollateral(
100
- depositAmount,
101
- yield exports.getTokenAddress(
102
- usdcTokenAddress.toString(),
103
- wallet.publicKey.toString()
104
- ),
105
- banks_1.SpotMarkets['devnet'][0].marketIndex
106
- );
107
- }
108
- yield user.subscribe();
109
- // Get current price
110
- const solMarketInfo = sdkConfig.PERP_MARKETS.find(
111
- (market) => market.baseAssetSymbol === 'SOL'
112
- );
113
- const currentMarketPrice = __2.calculateMarkPrice(
114
- clearingHouse.getMarketAccount(solMarketInfo.marketIndex),
115
- undefined
116
- );
117
- const formattedPrice = __2.convertToNumber(
118
- currentMarketPrice,
119
- __2.PRICE_PRECISION
120
- );
121
- console.log(`Current Market Price is $${formattedPrice}`);
122
- // Estimate the slippage for a $5000 LONG trade
123
- const solMarketAccount = clearingHouse.getMarketAccount(
124
- solMarketInfo.marketIndex
125
- );
126
- const longAmount = new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION);
127
- const slippage = __2.convertToNumber(
128
- __2.calculateTradeSlippage(
129
- __2.PositionDirection.LONG,
130
- longAmount,
131
- solMarketAccount,
132
- 'quote',
133
- undefined
134
- )[0],
135
- __2.PRICE_PRECISION
136
- );
137
- console.log(
138
- `Slippage for a $5000 LONG on the SOL market would be $${slippage}`
139
- );
140
- // Make a $5000 LONG trade
141
- yield clearingHouse.openPosition(
142
- __2.PositionDirection.LONG,
143
- longAmount,
144
- solMarketInfo.marketIndex
145
- );
146
- console.log(`LONGED $5000 SOL`);
147
- // Reduce the position by $2000
148
- const reduceAmount = new anchor_1.BN(2000).mul(__2.QUOTE_PRECISION);
149
- yield clearingHouse.openPosition(
150
- __2.PositionDirection.SHORT,
151
- reduceAmount,
152
- solMarketInfo.marketIndex
153
- );
154
- // Close the rest of the position
155
- yield clearingHouse.closePosition(solMarketInfo.marketIndex);
156
- });
157
- main();
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseTokenAccount = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- function parseTokenAccount(data) {
7
- const accountInfo = spl_token_1.AccountLayout.decode(data);
8
- accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
9
- accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
10
- accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
11
- if (accountInfo.delegateOption === 0) {
12
- accountInfo.delegate = null;
13
- // eslint-disable-next-line new-cap
14
- accountInfo.delegatedAmount = new spl_token_1.u64(0);
15
- }
16
- else {
17
- accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
18
- accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
19
- }
20
- accountInfo.isInitialized = accountInfo.state !== 0;
21
- accountInfo.isFrozen = accountInfo.state === 2;
22
- if (accountInfo.isNativeOption === 1) {
23
- accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
24
- accountInfo.isNative = true;
25
- }
26
- else {
27
- accountInfo.rentExemptReserve = null;
28
- accountInfo.isNative = false;
29
- }
30
- if (accountInfo.closeAuthorityOption === 0) {
31
- accountInfo.closeAuthority = null;
32
- }
33
- else {
34
- accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
35
- }
36
- return accountInfo;
37
- }
38
- exports.parseTokenAccount = parseTokenAccount;
package/src/tx/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
package/src/tx/utils.js DELETED
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapInTx = void 0;
4
- const web3_js_1 = require("@solana/web3.js");
5
- const COMPUTE_UNITS_DEFAULT = 200000;
6
- function wrapInTx(instruction, computeUnits = 600000 // TODO, requires less code change
7
- ) {
8
- const tx = new web3_js_1.Transaction();
9
- if (computeUnits != COMPUTE_UNITS_DEFAULT) {
10
- tx.add(web3_js_1.ComputeBudgetProgram.requestUnits({
11
- units: computeUnits,
12
- additionalFee: 0,
13
- }));
14
- }
15
- return tx.add(instruction);
16
- }
17
- exports.wrapInTx = wrapInTx;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.findComputeUnitConsumption = void 0;
13
- function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
14
- return __awaiter(this, void 0, void 0, function* () {
15
- const tx = yield connection.getTransaction(txSignature, { commitment });
16
- const computeUnits = [];
17
- const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
18
- tx.meta.logMessages.forEach((logMessage) => {
19
- const match = logMessage.match(regex);
20
- if (match && match[1]) {
21
- computeUnits.push(match[1]);
22
- }
23
- });
24
- return computeUnits;
25
- });
26
- }
27
- exports.findComputeUnitConsumption = findComputeUnitConsumption;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTokenAddress = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- const getTokenAddress = (mintAddress, userPubKey) => {
7
- return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
8
- };
9
- exports.getTokenAddress = getTokenAddress;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promiseTimeout = void 0;
4
- function promiseTimeout(promise, timeoutMs) {
5
- let timeoutId;
6
- const timeoutPromise = new Promise((resolve) => {
7
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
8
- });
9
- return Promise.race([promise, timeoutPromise]).then((result) => {
10
- clearTimeout(timeoutId);
11
- return result;
12
- });
13
- }
14
- exports.promiseTimeout = promiseTimeout;
package/src/util/tps.js DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.estimateTps = void 0;
13
- function estimateTps(programId, connection, failed) {
14
- return __awaiter(this, void 0, void 0, function* () {
15
- let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
16
- if (failed) {
17
- signatures = signatures.filter((signature) => signature.err);
18
- }
19
- const numberOfSignatures = signatures.length;
20
- if (numberOfSignatures === 0) {
21
- return 0;
22
- }
23
- return (numberOfSignatures /
24
- (signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
25
- });
26
- }
27
- exports.estimateTps = estimateTps;