@drift-labs/sdk 0.2.0-master.4 → 0.2.0-master.41

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 (247) hide show
  1. package/README.md +27 -27
  2. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  3. package/lib/accounts/bulkAccountLoader.js +36 -29
  4. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  5. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  6. package/lib/accounts/bulkUserSubscription.d.ts +2 -2
  7. package/lib/accounts/bulkUserSubscription.js +0 -1
  8. package/lib/accounts/fetch.d.ts +2 -1
  9. package/lib/accounts/fetch.js +9 -1
  10. package/lib/accounts/{pollingClearingHouseAccountSubscriber.d.ts → pollingDriftClientAccountSubscriber.d.ts} +20 -25
  11. package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +45 -49
  12. package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
  13. package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
  14. package/lib/accounts/pollingUserAccountSubscriber.d.ts +1 -1
  15. package/lib/accounts/pollingUserAccountSubscriber.js +5 -11
  16. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  17. package/lib/accounts/pollingUserStatsAccountSubscriber.js +107 -0
  18. package/lib/accounts/types.d.ts +26 -15
  19. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +49 -0
  20. package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +47 -45
  21. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  22. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  23. package/lib/addresses/marketAddresses.d.ts +1 -3
  24. package/lib/addresses/marketAddresses.js +1 -1
  25. package/lib/addresses/pda.d.ts +15 -9
  26. package/lib/addresses/pda.js +73 -35
  27. package/lib/adminClient.d.ts +65 -0
  28. package/lib/adminClient.js +637 -0
  29. package/lib/config.d.ts +9 -9
  30. package/lib/config.js +25 -21
  31. package/lib/constants/numericConstants.d.ts +30 -12
  32. package/lib/constants/numericConstants.js +41 -21
  33. package/lib/constants/perpMarkets.d.ts +18 -0
  34. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  35. package/lib/constants/spotMarkets.d.ts +19 -0
  36. package/lib/constants/spotMarkets.js +53 -0
  37. package/lib/dlob/DLOB.d.ts +82 -0
  38. package/lib/dlob/DLOB.js +694 -0
  39. package/lib/dlob/DLOBNode.d.ts +54 -0
  40. package/lib/dlob/DLOBNode.js +77 -0
  41. package/lib/dlob/NodeList.d.ts +27 -0
  42. package/lib/dlob/NodeList.js +144 -0
  43. package/lib/driftClient.d.ts +234 -0
  44. package/lib/driftClient.js +2108 -0
  45. package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +9 -9
  46. package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
  47. package/lib/events/eventList.js +3 -0
  48. package/lib/events/eventSubscriber.d.ts +5 -2
  49. package/lib/events/eventSubscriber.js +25 -11
  50. package/lib/events/fetchLogs.d.ts +13 -2
  51. package/lib/events/fetchLogs.js +40 -12
  52. package/lib/events/pollingLogProvider.d.ts +2 -1
  53. package/lib/events/pollingLogProvider.js +7 -3
  54. package/lib/events/sort.js +8 -11
  55. package/lib/events/types.d.ts +11 -3
  56. package/lib/events/types.js +8 -0
  57. package/lib/events/webSocketLogProvider.js +1 -1
  58. package/lib/examples/makeTradeExample.js +30 -18
  59. package/lib/factory/bigNum.d.ts +8 -4
  60. package/lib/factory/bigNum.js +109 -19
  61. package/lib/idl/drift.json +8386 -0
  62. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  63. package/lib/index.d.ts +30 -13
  64. package/lib/index.js +30 -13
  65. package/lib/math/amm.d.ts +9 -6
  66. package/lib/math/amm.js +91 -38
  67. package/lib/math/conversion.js +1 -1
  68. package/lib/math/exchangeStatus.d.ts +4 -0
  69. package/lib/math/exchangeStatus.js +18 -0
  70. package/lib/math/funding.d.ts +6 -6
  71. package/lib/math/funding.js +23 -21
  72. package/lib/math/insurance.d.ts +4 -0
  73. package/lib/math/insurance.js +27 -0
  74. package/lib/math/margin.d.ts +11 -0
  75. package/lib/math/margin.js +82 -0
  76. package/lib/math/market.d.ts +14 -9
  77. package/lib/math/market.js +70 -10
  78. package/lib/math/oracles.d.ts +4 -0
  79. package/lib/math/oracles.js +36 -8
  80. package/lib/math/orders.d.ts +16 -6
  81. package/lib/math/orders.js +97 -17
  82. package/lib/math/position.d.ts +27 -13
  83. package/lib/math/position.js +92 -36
  84. package/lib/math/repeg.js +17 -8
  85. package/lib/math/spotBalance.d.ts +22 -0
  86. package/lib/math/spotBalance.js +192 -0
  87. package/lib/math/spotMarket.d.ts +4 -0
  88. package/lib/math/spotMarket.js +8 -0
  89. package/lib/math/spotPosition.d.ts +6 -0
  90. package/lib/math/spotPosition.js +23 -0
  91. package/lib/math/trade.d.ts +10 -10
  92. package/lib/math/trade.js +27 -31
  93. package/lib/oracles/pythClient.js +1 -1
  94. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  95. package/lib/oracles/switchboardClient.js +1 -1
  96. package/lib/orderParams.d.ts +4 -4
  97. package/lib/orderParams.js +12 -4
  98. package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
  99. package/lib/serum/serumFulfillmentConfigMap.js +17 -0
  100. package/lib/serum/serumSubscriber.d.ts +27 -0
  101. package/lib/serum/serumSubscriber.js +56 -0
  102. package/lib/serum/types.d.ts +11 -0
  103. package/lib/{clearingHouseUserConfig.js → serum/types.js} +0 -0
  104. package/lib/slot/SlotSubscriber.d.ts +7 -0
  105. package/lib/slot/SlotSubscriber.js +3 -0
  106. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  107. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  108. package/lib/tx/retryTxSender.d.ts +1 -1
  109. package/lib/tx/retryTxSender.js +13 -4
  110. package/lib/tx/types.d.ts +1 -1
  111. package/lib/tx/utils.js +1 -1
  112. package/lib/types.d.ts +688 -216
  113. package/lib/types.js +153 -24
  114. package/lib/user.d.ts +228 -0
  115. package/lib/user.js +959 -0
  116. package/lib/userConfig.d.ts +14 -0
  117. package/lib/userConfig.js +2 -0
  118. package/lib/userMap/userMap.d.ts +41 -0
  119. package/lib/userMap/userMap.js +85 -0
  120. package/lib/userMap/userStatsMap.d.ts +19 -0
  121. package/lib/userMap/userStatsMap.js +68 -0
  122. package/lib/userName.d.ts +1 -0
  123. package/lib/userName.js +3 -2
  124. package/lib/userStats.d.ts +18 -0
  125. package/lib/userStats.js +49 -0
  126. package/lib/userStatsConfig.d.ts +14 -0
  127. package/lib/userStatsConfig.js +2 -0
  128. package/lib/util/computeUnits.js +1 -1
  129. package/lib/util/getTokenAddress.d.ts +2 -0
  130. package/lib/util/getTokenAddress.js +9 -0
  131. package/package.json +11 -4
  132. package/src/accounts/bulkAccountLoader.ts +44 -34
  133. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  134. package/src/accounts/bulkUserSubscription.ts +2 -3
  135. package/src/accounts/fetch.ts +27 -2
  136. package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +65 -75
  137. package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
  138. package/src/accounts/pollingUserAccountSubscriber.ts +5 -12
  139. package/src/accounts/pollingUserStatsAccountSubscriber.ts +166 -0
  140. package/src/accounts/types.ts +35 -15
  141. package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +78 -73
  142. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  143. package/src/addresses/marketAddresses.ts +3 -4
  144. package/src/addresses/pda.ts +105 -33
  145. package/src/adminClient.ts +1207 -0
  146. package/src/assert/assert.js +9 -0
  147. package/src/config.ts +37 -31
  148. package/src/constants/numericConstants.ts +58 -24
  149. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  150. package/src/constants/spotMarkets.ts +73 -0
  151. package/src/dlob/DLOB.ts +1120 -0
  152. package/src/dlob/DLOBNode.ts +155 -0
  153. package/src/dlob/NodeList.ts +195 -0
  154. package/src/driftClient.ts +3594 -0
  155. package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +9 -8
  156. package/src/events/eventList.js +77 -0
  157. package/src/events/eventList.ts +3 -0
  158. package/src/events/eventSubscriber.ts +36 -14
  159. package/src/events/fetchLogs.ts +55 -13
  160. package/src/events/pollingLogProvider.ts +11 -3
  161. package/src/events/sort.ts +11 -15
  162. package/src/events/types.ts +27 -2
  163. package/src/events/webSocketLogProvider.ts +1 -1
  164. package/src/examples/makeTradeExample.js +157 -0
  165. package/src/examples/makeTradeExample.ts +44 -28
  166. package/src/factory/bigNum.ts +150 -22
  167. package/src/idl/drift.json +8386 -0
  168. package/src/idl/pyth.json +98 -2
  169. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  170. package/src/index.ts +30 -13
  171. package/src/math/amm.ts +161 -48
  172. package/src/math/conversion.ts +2 -2
  173. package/src/math/exchangeStatus.ts +31 -0
  174. package/src/math/funding.ts +41 -31
  175. package/src/math/insurance.ts +35 -0
  176. package/src/math/margin.ts +133 -0
  177. package/src/math/market.ts +143 -14
  178. package/src/math/oracles.ts +63 -9
  179. package/src/math/orders.ts +168 -26
  180. package/src/math/position.ts +136 -58
  181. package/src/math/repeg.ts +19 -9
  182. package/src/math/spotBalance.ts +319 -0
  183. package/src/math/spotMarket.ts +9 -0
  184. package/src/math/spotPosition.ts +47 -0
  185. package/src/math/trade.ts +33 -37
  186. package/src/oracles/pythClient.ts +2 -2
  187. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  188. package/src/oracles/switchboardClient.ts +2 -2
  189. package/src/orderParams.ts +16 -8
  190. package/src/serum/serumFulfillmentConfigMap.ts +26 -0
  191. package/src/serum/serumSubscriber.ts +99 -0
  192. package/src/serum/types.ts +13 -0
  193. package/src/slot/SlotSubscriber.ts +11 -1
  194. package/src/token/index.js +38 -0
  195. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  196. package/src/tx/retryTxSender.ts +16 -5
  197. package/src/tx/types.js +2 -0
  198. package/src/tx/types.ts +2 -1
  199. package/src/tx/utils.js +17 -0
  200. package/src/tx/utils.ts +1 -1
  201. package/src/types.ts +650 -189
  202. package/src/user.ts +1599 -0
  203. package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
  204. package/src/userMap/userMap.ts +124 -0
  205. package/src/userMap/userStatsMap.ts +108 -0
  206. package/src/userName.ts +2 -1
  207. package/src/userStats.ts +75 -0
  208. package/src/userStatsConfig.ts +18 -0
  209. package/src/util/computeUnits.js +21 -11
  210. package/src/util/computeUnits.ts +1 -1
  211. package/src/util/getTokenAddress.js +9 -0
  212. package/src/util/getTokenAddress.ts +18 -0
  213. package/src/util/promiseTimeout.js +14 -0
  214. package/src/util/tps.js +27 -0
  215. package/tests/bn/test.ts +46 -11
  216. package/tests/dlob/helpers.ts +620 -0
  217. package/tests/dlob/test.ts +4586 -0
  218. package/yarn-error.log +3160 -0
  219. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
  220. package/lib/admin.d.ts +0 -44
  221. package/lib/admin.js +0 -433
  222. package/lib/clearingHouse.d.ts +0 -133
  223. package/lib/clearingHouse.js +0 -931
  224. package/lib/clearingHouseUser.d.ts +0 -187
  225. package/lib/clearingHouseUser.js +0 -643
  226. package/lib/clearingHouseUserConfig.d.ts +0 -14
  227. package/lib/constants/banks.d.ts +0 -16
  228. package/lib/constants/banks.js +0 -34
  229. package/lib/constants/markets.d.ts +0 -19
  230. package/lib/idl/clearing_house.json +0 -3998
  231. package/lib/math/bankBalance.d.ts +0 -9
  232. package/lib/math/bankBalance.js +0 -75
  233. package/lib/math/state.d.ts +0 -8
  234. package/lib/math/state.js +0 -15
  235. package/lib/orders.d.ts +0 -8
  236. package/lib/orders.js +0 -134
  237. package/src/admin.ts +0 -722
  238. package/src/clearingHouse.ts +0 -1451
  239. package/src/clearingHouseUser.ts +0 -989
  240. package/src/constants/banks.ts +0 -43
  241. package/src/idl/clearing_house.json +0 -3998
  242. package/src/math/bankBalance.ts +0 -112
  243. package/src/math/state.ts +0 -14
  244. package/src/math/utils.js +0 -27
  245. package/src/math/utils.js.map +0 -1
  246. package/src/orders.ts +0 -244
  247. package/src/util/computeUnits.js.map +0 -1
@@ -1,26 +1,27 @@
1
1
  import { ConfirmOptions, Connection, PublicKey } from '@solana/web3.js';
2
2
  import { IWallet } from './types';
3
- import { BN } from '@project-serum/anchor';
4
3
  import { OracleInfo } from './oracles/types';
5
4
  import { BulkAccountLoader } from './accounts/bulkAccountLoader';
6
5
  import { DriftEnv } from './config';
7
6
 
8
- export type ClearingHouseConfig = {
7
+ export type DriftClientConfig = {
9
8
  connection: Connection;
10
9
  wallet: IWallet;
11
10
  programID: PublicKey;
12
- accountSubscription?: ClearingHouseSubscriptionConfig;
11
+ accountSubscription?: DriftClientSubscriptionConfig;
13
12
  opts?: ConfirmOptions;
14
13
  txSenderConfig?: TxSenderConfig;
15
- userIds?: number[];
16
- activeUserId?: number;
17
- marketIndexes?: BN[];
18
- bankIndexes?: BN[];
14
+ subAccountIds?: number[];
15
+ activeSubAccountId?: number;
16
+ perpMarketIndexes?: number[];
17
+ spotMarketIndexes?: number[];
19
18
  oracleInfos?: OracleInfo[];
20
19
  env?: DriftEnv;
20
+ userStats?: boolean;
21
+ authority?: PublicKey; // explicitly pass an authority if signer is delegate
21
22
  };
22
23
 
23
- type ClearingHouseSubscriptionConfig =
24
+ type DriftClientSubscriptionConfig =
24
25
  | {
25
26
  type: 'websocket';
26
27
  }
@@ -0,0 +1,77 @@
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;
@@ -53,7 +53,10 @@ export class EventList<Type extends EventType> {
53
53
  newNode.next = currentNode.next;
54
54
  if (currentNode.next !== undefined) {
55
55
  newNode.next.prev = newNode;
56
+ } else {
57
+ this.tail = newNode;
56
58
  }
59
+
57
60
  currentNode.next = newNode;
58
61
  newNode.prev = currentNode;
59
62
  }
@@ -25,6 +25,9 @@ export class EventSubscriber {
25
25
  private awaitTxResolver = new Map<string, () => void>();
26
26
  private logProvider: LogProvider;
27
27
  public eventEmitter: StrictEventEmitter<EventEmitter, EventSubscriberEvents>;
28
+ private lastSeenSlot: number;
29
+ private lastSeenBlockTime: number | undefined;
30
+ public lastSeenTxSig: string;
28
31
 
29
32
  public constructor(
30
33
  private connection: Connection,
@@ -62,25 +65,29 @@ export class EventSubscriber {
62
65
  }
63
66
  }
64
67
 
65
- public subscribe(): boolean {
66
- if (this.logProvider.isSubscribed()) {
67
- return true;
68
- }
68
+ public async subscribe(): Promise<boolean> {
69
+ try {
70
+ if (this.logProvider.isSubscribed()) {
71
+ return true;
72
+ }
69
73
 
70
- this.fetchPreviousTx().catch((e) => {
74
+ this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime) => {
75
+ this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime);
76
+ }, true);
77
+
78
+ return true;
79
+ } catch (e) {
71
80
  console.error('Error fetching previous txs in event subscriber');
72
81
  console.error(e);
73
- });
74
-
75
- return this.logProvider.subscribe((txSig, slot, logs) => {
76
- this.handleTxLogs(txSig, slot, logs);
77
- });
82
+ return false;
83
+ }
78
84
  }
79
85
 
80
86
  private handleTxLogs(
81
87
  txSig: TransactionSignature,
82
88
  slot: number,
83
- logs: string[]
89
+ logs: string[],
90
+ mostRecentBlockTime: number | undefined
84
91
  ): void {
85
92
  if (this.txEventCache.has(txSig)) {
86
93
  return;
@@ -89,6 +96,10 @@ export class EventSubscriber {
89
96
  const wrappedEvents = this.parseEventsFromLogs(txSig, slot, logs);
90
97
  for (const wrappedEvent of wrappedEvents) {
91
98
  this.eventListMap.get(wrappedEvent.eventType).insert(wrappedEvent);
99
+ }
100
+
101
+ // dont emit event till we've added all the events to the eventListMap
102
+ for (const wrappedEvent of wrappedEvents) {
92
103
  this.eventEmitter.emit('newEvent', wrappedEvent);
93
104
  }
94
105
 
@@ -98,11 +109,22 @@ export class EventSubscriber {
98
109
  this.awaitTxResolver.delete(txSig);
99
110
  }
100
111
 
112
+ if (slot > this.lastSeenSlot) {
113
+ this.lastSeenTxSig = txSig;
114
+ }
115
+
116
+ if (
117
+ this.lastSeenBlockTime === undefined ||
118
+ mostRecentBlockTime > this.lastSeenBlockTime
119
+ ) {
120
+ this.lastSeenBlockTime = mostRecentBlockTime;
121
+ }
122
+
101
123
  this.txEventCache.add(txSig, wrappedEvents);
102
124
  }
103
125
 
104
- private async fetchPreviousTx(): Promise<void> {
105
- if (!this.options.untilTx) {
126
+ public async fetchPreviousTx(fetchMax?: boolean): Promise<void> {
127
+ if (!this.options.untilTx && !fetchMax) {
106
128
  return;
107
129
  }
108
130
 
@@ -126,7 +148,7 @@ export class EventSubscriber {
126
148
  beforeTx = response.earliestTx;
127
149
 
128
150
  for (const { txSig, slot, logs } of response.transactionLogs) {
129
- this.handleTxLogs(txSig, slot, logs);
151
+ this.handleTxLogs(txSig, slot, logs, response.mostRecentBlockTime);
130
152
  }
131
153
  }
132
154
  }
@@ -1,35 +1,51 @@
1
+ import { Program } from '@project-serum/anchor';
1
2
  import {
2
3
  Connection,
3
4
  Finality,
4
5
  PublicKey,
6
+ TransactionResponse,
5
7
  TransactionSignature,
6
8
  } from '@solana/web3.js';
9
+ import { WrappedEvents } from './types';
7
10
 
8
11
  type Log = { txSig: TransactionSignature; slot: number; logs: string[] };
9
12
  type FetchLogsResponse = {
10
13
  earliestTx: string;
11
14
  mostRecentTx: string;
15
+ earliestSlot: number;
16
+ mostRecentSlot: number;
12
17
  transactionLogs: Log[];
18
+ mostRecentBlockTime: number | undefined;
13
19
  };
14
20
 
21
+ function mapTransactionResponseToLog(transaction: TransactionResponse): Log {
22
+ return {
23
+ txSig: transaction.transaction.signatures[0],
24
+ slot: transaction.slot,
25
+ logs: transaction.meta.logMessages,
26
+ };
27
+ }
28
+
15
29
  export async function fetchLogs(
16
30
  connection: Connection,
17
31
  programId: PublicKey,
18
32
  finality: Finality,
19
33
  beforeTx?: TransactionSignature,
20
- untilTx?: TransactionSignature
21
- ): Promise<FetchLogsResponse | undefined> {
34
+ untilTx?: TransactionSignature,
35
+ limit?: number
36
+ ): Promise<FetchLogsResponse> {
22
37
  const signatures = await connection.getSignaturesForAddress(
23
38
  programId,
24
39
  {
25
40
  before: beforeTx,
26
41
  until: untilTx,
42
+ limit,
27
43
  },
28
44
  finality
29
45
  );
30
46
 
31
47
  const sortedSignatures = signatures.sort((a, b) =>
32
- a.slot < b.slot ? -1 : 1
48
+ a.slot === b.slot ? 0 : a.slot < b.slot ? -1 : 1
33
49
  );
34
50
 
35
51
  const filteredSignatures = sortedSignatures.filter(
@@ -51,24 +67,22 @@ export async function fetchLogs(
51
67
  );
52
68
 
53
69
  return transactions.map((transaction) => {
54
- return {
55
- txSig: transaction.transaction.signatures[0],
56
- slot: transaction.slot,
57
- logs: transaction.meta.logMessages,
58
- };
70
+ return mapTransactionResponseToLog(transaction);
59
71
  });
60
72
  })
61
73
  )
62
74
  ).flat();
63
75
 
64
- const earliestTx = filteredSignatures[0].signature;
65
- const mostRecentTx =
66
- filteredSignatures[filteredSignatures.length - 1].signature;
76
+ const earliest = filteredSignatures[0];
77
+ const mostRecent = filteredSignatures[filteredSignatures.length - 1];
67
78
 
68
79
  return {
69
80
  transactionLogs: transactionLogs,
70
- earliestTx: earliestTx,
71
- mostRecentTx: mostRecentTx,
81
+ earliestTx: earliest.signature,
82
+ mostRecentTx: mostRecent.signature,
83
+ earliestSlot: earliest.slot,
84
+ mostRecentSlot: mostRecent.slot,
85
+ mostRecentBlockTime: mostRecent.blockTime,
72
86
  };
73
87
  }
74
88
 
@@ -78,3 +92,31 @@ function chunk<T>(array: readonly T[], size: number): T[][] {
78
92
  .map((_, index) => index * size)
79
93
  .map((begin) => array.slice(begin, begin + size));
80
94
  }
95
+
96
+ export class LogParser {
97
+ private program: Program;
98
+
99
+ constructor(program: Program) {
100
+ this.program = program;
101
+ }
102
+
103
+ public parseEventsFromTransaction(
104
+ transaction: TransactionResponse
105
+ ): WrappedEvents {
106
+ const transactionLogObject = mapTransactionResponseToLog(transaction);
107
+
108
+ return this.parseEventsFromLogs(transactionLogObject);
109
+ }
110
+
111
+ public parseEventsFromLogs(event: Log): WrappedEvents {
112
+ const records: WrappedEvents = [];
113
+ // @ts-ignore
114
+ this.program._events._eventParser.parseLogs(event.logs, (eventLog) => {
115
+ eventLog.data.txSig = event.txSig;
116
+ eventLog.data.slot = event.slot;
117
+ eventLog.data.eventType = eventLog.name;
118
+ records.push(eventLog.data);
119
+ });
120
+ return records;
121
+ }
122
+ }
@@ -13,6 +13,7 @@ export class PollingLogProvider implements LogProvider {
13
13
  private intervalId: NodeJS.Timer;
14
14
  private mostRecentSeenTx?: TransactionSignature;
15
15
  private mutex: number;
16
+ private firstFetch = true;
16
17
 
17
18
  public constructor(
18
19
  private connection: Connection,
@@ -23,7 +24,10 @@ export class PollingLogProvider implements LogProvider {
23
24
  this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
24
25
  }
25
26
 
26
- public subscribe(callback: logProviderCallback): boolean {
27
+ public subscribe(
28
+ callback: logProviderCallback,
29
+ skipHistory?: boolean
30
+ ): boolean {
27
31
  if (this.intervalId) {
28
32
  return true;
29
33
  }
@@ -40,9 +44,13 @@ export class PollingLogProvider implements LogProvider {
40
44
  this.programId,
41
45
  this.finality,
42
46
  undefined,
43
- this.mostRecentSeenTx
47
+ this.mostRecentSeenTx,
48
+ // If skipping history, only fetch one log back, not the maximum amount available
49
+ skipHistory && this.firstFetch ? 1 : undefined
44
50
  );
45
51
 
52
+ this.firstFetch = false;
53
+
46
54
  if (response === undefined) {
47
55
  return;
48
56
  }
@@ -50,7 +58,7 @@ export class PollingLogProvider implements LogProvider {
50
58
  const { mostRecentTx, transactionLogs } = response;
51
59
 
52
60
  for (const { txSig, slot, logs } of transactionLogs) {
53
- callback(txSig, slot, logs);
61
+ callback(txSig, slot, logs, response.mostRecentBlockTime);
54
62
  }
55
63
 
56
64
  this.mostRecentSeenTx = mostRecentTx;
@@ -6,8 +6,8 @@ import {
6
6
  SortFn,
7
7
  Event,
8
8
  } from './types';
9
- import { OrderRecord } from '../types';
10
- import { PublicKey, ZERO } from '../index';
9
+ import { OrderActionRecord } from '../types';
10
+ import { ZERO } from '../index';
11
11
 
12
12
  function clientSortAscFn(): 'less than' {
13
13
  return 'less than';
@@ -24,21 +24,17 @@ function defaultBlockchainSortFn(
24
24
  return currentEvent.slot <= newEvent.slot ? 'less than' : 'greater than';
25
25
  }
26
26
 
27
- function orderRecordSortFn(
28
- currentEvent: Event<OrderRecord>,
29
- newEvent: Event<OrderRecord>
27
+ function orderActionRecordSortFn(
28
+ currentEvent: Event<OrderActionRecord>,
29
+ newEvent: Event<OrderActionRecord>
30
30
  ): 'less than' | 'greater than' {
31
- const currentEventMarketIndex = !currentEvent.maker.equals(PublicKey.default)
32
- ? currentEvent.makerOrder.marketIndex
33
- : currentEvent.takerOrder.marketIndex;
34
- const newEventMarketIndex = !newEvent.maker.equals(PublicKey.default)
35
- ? newEvent.makerOrder.marketIndex
36
- : newEvent.takerOrder.marketIndex;
37
- if (!currentEventMarketIndex.eq(newEventMarketIndex)) {
31
+ const currentEventMarketIndex = currentEvent.marketIndex;
32
+ const newEventMarketIndex = newEvent.marketIndex;
33
+ if (currentEventMarketIndex !== newEventMarketIndex) {
38
34
  return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
39
35
  }
40
36
 
41
- if (currentEvent.fillRecordId.gt(ZERO) && newEvent.fillRecordId.gt(ZERO)) {
37
+ if (currentEvent.fillRecordId?.gt(ZERO) && newEvent.fillRecordId?.gt(ZERO)) {
42
38
  return currentEvent.fillRecordId.lte(newEvent.fillRecordId)
43
39
  ? 'less than'
44
40
  : 'greater than';
@@ -57,8 +53,8 @@ export function getSortFn(
57
53
  }
58
54
 
59
55
  switch (eventType) {
60
- case 'OrderRecord':
61
- return orderRecordSortFn;
56
+ case 'OrderActionRecord':
57
+ return orderActionRecordSortFn;
62
58
  default:
63
59
  return defaultBlockchainSortFn;
64
60
  }
@@ -4,7 +4,15 @@ import {
4
4
  FundingPaymentRecord,
5
5
  FundingRateRecord,
6
6
  LiquidationRecord,
7
+ NewUserRecord,
8
+ OrderActionRecord,
7
9
  OrderRecord,
10
+ SettlePnlRecord,
11
+ LPRecord,
12
+ InsuranceFundRecord,
13
+ SpotInterestRecord,
14
+ InsuranceFundStakeRecord,
15
+ CurveRecord,
8
16
  } from '../index';
9
17
 
10
18
  export type EventSubscriptionOptions = {
@@ -26,7 +34,15 @@ export const DefaultEventSubscriptionOptions: EventSubscriptionOptions = {
26
34
  'FundingPaymentRecord',
27
35
  'LiquidationRecord',
28
36
  'OrderRecord',
37
+ 'OrderActionRecord',
29
38
  'FundingRateRecord',
39
+ 'NewUserRecord',
40
+ 'SettlePnlRecord',
41
+ 'LPRecord',
42
+ 'InsuranceFundRecord',
43
+ 'SpotInterestRecord',
44
+ 'InsuranceFundStakeRecord',
45
+ 'CurveRecord',
30
46
  ],
31
47
  maxEventsPerType: 4096,
32
48
  orderBy: 'blockchain',
@@ -59,6 +75,14 @@ export type EventMap = {
59
75
  LiquidationRecord: Event<LiquidationRecord>;
60
76
  FundingRateRecord: Event<FundingRateRecord>;
61
77
  OrderRecord: Event<OrderRecord>;
78
+ OrderActionRecord: Event<OrderActionRecord>;
79
+ SettlePnlRecord: Event<SettlePnlRecord>;
80
+ NewUserRecord: Event<NewUserRecord>;
81
+ LPRecord: Event<LPRecord>;
82
+ InsuranceFundRecord: Event<InsuranceFundRecord>;
83
+ SpotInterestRecord: Event<SpotInterestRecord>;
84
+ InsuranceFundStakeRecord: Event<InsuranceFundStakeRecord>;
85
+ CurveRecord: Event<CurveRecord>;
62
86
  };
63
87
 
64
88
  export type EventType = keyof EventMap;
@@ -75,12 +99,13 @@ export type SortFn = (
75
99
  export type logProviderCallback = (
76
100
  txSig: TransactionSignature,
77
101
  slot: number,
78
- logs: string[]
102
+ logs: string[],
103
+ mostRecentBlockTime: number | undefined
79
104
  ) => void;
80
105
 
81
106
  export interface LogProvider {
82
107
  isSubscribed(): boolean;
83
- subscribe(callback: logProviderCallback): boolean;
108
+ subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
84
109
  unsubscribe(): Promise<boolean>;
85
110
  }
86
111
 
@@ -17,7 +17,7 @@ export class WebSocketLogProvider implements LogProvider {
17
17
  this.subscriptionId = this.connection.onLogs(
18
18
  this.programId,
19
19
  (logs, ctx) => {
20
- callback(logs.signature, ctx.slot, logs.logs);
20
+ callback(logs.signature, ctx.slot, logs.logs, undefined);
21
21
  },
22
22
  this.commitment
23
23
  );
@@ -0,0 +1,157 @@
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();