@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31

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 (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +42 -26
  20. package/lib/admin.js +228 -81
  21. package/lib/clearingHouse.d.ts +130 -49
  22. package/lib/clearingHouse.js +1256 -367
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +51 -39
  25. package/lib/clearingHouseUser.js +408 -191
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +25 -12
  33. package/lib/constants/numericConstants.js +35 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +74 -0
  39. package/lib/dlob/DLOB.js +595 -0
  40. package/lib/dlob/DLOBNode.d.ts +54 -0
  41. package/lib/dlob/DLOBNode.js +85 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +139 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +8 -2
  53. package/lib/events/types.js +6 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +2 -0
  56. package/lib/factory/bigNum.js +48 -10
  57. package/lib/idl/clearing_house.json +4889 -1529
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +9 -6
  62. package/lib/math/amm.js +91 -66
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +72 -10
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +192 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +32 -39
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +566 -138
  106. package/lib/types.js +129 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +12 -6
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +452 -147
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2066 -467
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -294
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +48 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +73 -0
  136. package/src/dlob/DLOB.ts +953 -0
  137. package/src/dlob/DLOBNode.ts +167 -0
  138. package/src/dlob/NodeList.ts +189 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +19 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +65 -13
  149. package/src/idl/clearing_house.json +4889 -1529
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +171 -88
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +145 -14
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +319 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +53 -59
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +533 -140
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +24 -10
  191. package/tests/dlob/helpers.ts +397 -0
  192. package/tests/dlob/test.ts +3688 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -0,0 +1,167 @@
1
+ import {
2
+ isOneOfVariant,
3
+ AMM_RESERVE_PRECISION,
4
+ BN,
5
+ convertToNumber,
6
+ getLimitPrice,
7
+ isVariant,
8
+ SpotMarketAccount,
9
+ PerpMarketAccount,
10
+ PRICE_PRECISION,
11
+ OraclePriceData,
12
+ Order,
13
+ ZERO,
14
+ } from '..';
15
+ import { PublicKey } from '@solana/web3.js';
16
+ import { getOrderSignature } from './NodeList';
17
+
18
+ export interface DLOBNode {
19
+ getPrice(oraclePriceData: OraclePriceData, slot: number): BN;
20
+ isVammNode(): boolean;
21
+ order: Order | undefined;
22
+ isBaseFilled(): boolean;
23
+ haveFilled: boolean;
24
+ userAccount: PublicKey | undefined;
25
+ market: SpotMarketAccount | PerpMarketAccount;
26
+ }
27
+
28
+ export abstract class OrderNode implements DLOBNode {
29
+ order: Order;
30
+ market: SpotMarketAccount | PerpMarketAccount;
31
+ userAccount: PublicKey;
32
+ sortValue: BN;
33
+ haveFilled = false;
34
+ haveTrigger = false;
35
+
36
+ constructor(
37
+ order: Order,
38
+ market: SpotMarketAccount | PerpMarketAccount,
39
+ userAccount: PublicKey
40
+ ) {
41
+ this.order = order;
42
+ this.market = market;
43
+ this.userAccount = userAccount;
44
+ this.sortValue = this.getSortValue(order);
45
+ }
46
+
47
+ abstract getSortValue(order: Order): BN;
48
+
49
+ public getLabel(): string {
50
+ let msg = `Order ${getOrderSignature(
51
+ this.order.orderId,
52
+ this.userAccount
53
+ )}`;
54
+ msg += ` ${isVariant(this.order.direction, 'long') ? 'LONG' : 'SHORT'} `;
55
+ msg += `${convertToNumber(
56
+ this.order.baseAssetAmount,
57
+ AMM_RESERVE_PRECISION
58
+ ).toFixed(3)}`;
59
+ if (this.order.price.gt(ZERO)) {
60
+ msg += ` @ ${convertToNumber(this.order.price, PRICE_PRECISION).toFixed(
61
+ 3
62
+ )}`;
63
+ }
64
+ if (this.order.triggerPrice.gt(ZERO)) {
65
+ msg += ` ${
66
+ isVariant(this.order.triggerCondition, 'below') ? 'BELOW' : 'ABOVE'
67
+ }`;
68
+ msg += ` ${convertToNumber(
69
+ this.order.triggerPrice,
70
+ PRICE_PRECISION
71
+ ).toFixed(3)}`;
72
+ }
73
+ return msg;
74
+ }
75
+
76
+ getPrice(oraclePriceData: OraclePriceData, slot: number): BN {
77
+ if (isOneOfVariant(this.order.marketType, ['spot'])) {
78
+ return getLimitPrice(this.order, oraclePriceData, slot);
79
+ } else if (isOneOfVariant(this.order.marketType, ['perp'])) {
80
+ return getLimitPrice(
81
+ this.order,
82
+ oraclePriceData,
83
+ slot,
84
+ this.market as PerpMarketAccount
85
+ );
86
+ } else {
87
+ console.error(`Unknown market type: ${this.order.marketType}`);
88
+ }
89
+ }
90
+
91
+ isBaseFilled(): boolean {
92
+ return this.order.baseAssetAmountFilled.eq(this.order.baseAssetAmount);
93
+ }
94
+
95
+ isVammNode(): boolean {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ export class LimitOrderNode extends OrderNode {
101
+ next?: LimitOrderNode;
102
+ previous?: LimitOrderNode;
103
+
104
+ getSortValue(order: Order): BN {
105
+ return order.price;
106
+ }
107
+ }
108
+
109
+ export class FloatingLimitOrderNode extends OrderNode {
110
+ next?: FloatingLimitOrderNode;
111
+ previous?: FloatingLimitOrderNode;
112
+
113
+ getSortValue(order: Order): BN {
114
+ return order.oraclePriceOffset;
115
+ }
116
+ }
117
+
118
+ export class MarketOrderNode extends OrderNode {
119
+ next?: MarketOrderNode;
120
+ previous?: MarketOrderNode;
121
+
122
+ getSortValue(order: Order): BN {
123
+ return order.slot;
124
+ }
125
+ }
126
+
127
+ export class TriggerOrderNode extends OrderNode {
128
+ next?: TriggerOrderNode;
129
+ previous?: TriggerOrderNode;
130
+
131
+ getSortValue(order: Order): BN {
132
+ return order.triggerPrice;
133
+ }
134
+ }
135
+
136
+ export type DLOBNodeMap = {
137
+ limit: LimitOrderNode;
138
+ floatingLimit: FloatingLimitOrderNode;
139
+ market: MarketOrderNode;
140
+ trigger: TriggerOrderNode;
141
+ };
142
+
143
+ export type DLOBNodeType =
144
+ | 'limit'
145
+ | 'floatingLimit'
146
+ | 'market'
147
+ | ('trigger' & keyof DLOBNodeMap);
148
+
149
+ export function createNode<T extends DLOBNodeType>(
150
+ nodeType: T,
151
+ order: Order,
152
+ market: SpotMarketAccount | PerpMarketAccount,
153
+ userAccount: PublicKey
154
+ ): DLOBNodeMap[T] {
155
+ switch (nodeType) {
156
+ case 'floatingLimit':
157
+ return new FloatingLimitOrderNode(order, market, userAccount);
158
+ case 'limit':
159
+ return new LimitOrderNode(order, market, userAccount);
160
+ case 'market':
161
+ return new MarketOrderNode(order, market, userAccount);
162
+ case 'trigger':
163
+ return new TriggerOrderNode(order, market, userAccount);
164
+ default:
165
+ throw Error(`Unknown DLOBNode type ${nodeType}`);
166
+ }
167
+ }
@@ -0,0 +1,189 @@
1
+ import {
2
+ BN,
3
+ isVariant,
4
+ MarketTypeStr,
5
+ Order,
6
+ PerpMarketAccount,
7
+ SpotMarketAccount,
8
+ } from '..';
9
+ import { PublicKey } from '@solana/web3.js';
10
+ import { createNode, DLOBNode, DLOBNodeMap } from './DLOBNode';
11
+
12
+ export type SortDirection = 'asc' | 'desc';
13
+
14
+ export function getOrderSignature(
15
+ orderId: number,
16
+ userAccount: PublicKey
17
+ ): string {
18
+ return `${userAccount.toString()}-${orderId.toString()}`;
19
+ }
20
+
21
+ export interface DLOBNodeGenerator {
22
+ getGenerator(): Generator<DLOBNode>;
23
+ }
24
+
25
+ export class NodeList<NodeType extends keyof DLOBNodeMap>
26
+ implements DLOBNodeGenerator
27
+ {
28
+ head?: DLOBNodeMap[NodeType];
29
+ length = 0;
30
+ nodeMap = new Map<string, DLOBNodeMap[NodeType]>();
31
+
32
+ constructor(
33
+ private nodeType: NodeType,
34
+ private sortDirection: SortDirection
35
+ ) {}
36
+
37
+ public insert(
38
+ order: Order,
39
+ marketType: MarketTypeStr,
40
+ market: PerpMarketAccount | SpotMarketAccount,
41
+ userAccount: PublicKey
42
+ ): void {
43
+ if (isVariant(order.status, 'init')) {
44
+ return;
45
+ }
46
+
47
+ if (marketType === 'spot') {
48
+ market = market as SpotMarketAccount;
49
+ } else if (marketType === 'perp') {
50
+ market = market as PerpMarketAccount;
51
+ }
52
+
53
+ const newNode = createNode(this.nodeType, order, market, userAccount);
54
+
55
+ const orderSignature = getOrderSignature(order.orderId, userAccount);
56
+ if (this.nodeMap.has(orderSignature)) {
57
+ return;
58
+ }
59
+ this.nodeMap.set(orderSignature, newNode);
60
+
61
+ this.length += 1;
62
+
63
+ if (this.head === undefined) {
64
+ this.head = newNode;
65
+ return;
66
+ }
67
+
68
+ if (this.prependNode(this.head, newNode)) {
69
+ this.head.previous = newNode;
70
+ newNode.next = this.head;
71
+ this.head = newNode;
72
+ return;
73
+ }
74
+
75
+ let currentNode = this.head;
76
+ while (
77
+ currentNode.next !== undefined &&
78
+ !this.prependNode(currentNode.next, newNode)
79
+ ) {
80
+ currentNode = currentNode.next;
81
+ }
82
+
83
+ newNode.next = currentNode.next;
84
+ if (currentNode.next !== undefined) {
85
+ newNode.next.previous = newNode;
86
+ }
87
+ currentNode.next = newNode;
88
+ newNode.previous = currentNode;
89
+ }
90
+
91
+ prependNode(
92
+ currentNode: DLOBNodeMap[NodeType],
93
+ newNode: DLOBNodeMap[NodeType]
94
+ ): boolean {
95
+ const currentOrder = currentNode.order;
96
+ const newOrder = newNode.order;
97
+
98
+ const currentOrderSortPrice = currentNode.sortValue;
99
+ const newOrderSortPrice = newNode.sortValue;
100
+
101
+ if (newOrderSortPrice.eq(currentOrderSortPrice)) {
102
+ return newOrder.ts.lt(currentOrder.ts);
103
+ }
104
+
105
+ if (this.sortDirection === 'asc') {
106
+ return newOrderSortPrice.lt(currentOrderSortPrice);
107
+ } else {
108
+ return newOrderSortPrice.gt(currentOrderSortPrice);
109
+ }
110
+ }
111
+
112
+ public update(order: Order, userAccount: PublicKey): void {
113
+ const orderId = getOrderSignature(order.orderId, userAccount);
114
+ if (this.nodeMap.has(orderId)) {
115
+ const node = this.nodeMap.get(orderId);
116
+ Object.assign(node.order, order);
117
+ node.haveFilled = false;
118
+ }
119
+ }
120
+
121
+ public remove(order: Order, userAccount: PublicKey): void {
122
+ const orderId = getOrderSignature(order.orderId, userAccount);
123
+ if (this.nodeMap.has(orderId)) {
124
+ const node = this.nodeMap.get(orderId);
125
+ if (node.next) {
126
+ node.next.previous = node.previous;
127
+ }
128
+ if (node.previous) {
129
+ node.previous.next = node.next;
130
+ }
131
+
132
+ if (this.head && node.order.orderId === this.head.order.orderId) {
133
+ this.head = node.next;
134
+ }
135
+
136
+ node.previous = undefined;
137
+ node.next = undefined;
138
+
139
+ this.nodeMap.delete(orderId);
140
+
141
+ this.length--;
142
+ }
143
+ }
144
+
145
+ *getGenerator(): Generator<DLOBNode> {
146
+ let node = this.head;
147
+ while (node !== undefined) {
148
+ yield node;
149
+ node = node.next;
150
+ }
151
+ }
152
+
153
+ public has(order: Order, userAccount: PublicKey): boolean {
154
+ return this.nodeMap.has(getOrderSignature(order.orderId, userAccount));
155
+ }
156
+
157
+ public print(): void {
158
+ let currentNode = this.head;
159
+ while (currentNode !== undefined) {
160
+ console.log(currentNode.getLabel());
161
+ currentNode = currentNode.next;
162
+ }
163
+ }
164
+
165
+ public printTop(): void {
166
+ if (this.head) {
167
+ console.log(this.sortDirection.toUpperCase(), this.head.getLabel());
168
+ } else {
169
+ console.log('---');
170
+ }
171
+ }
172
+ }
173
+
174
+ export function* getVammNodeGenerator(
175
+ price: BN | undefined
176
+ ): Generator<DLOBNode> {
177
+ if (!price) {
178
+ return;
179
+ }
180
+ yield {
181
+ getPrice: () => price,
182
+ isVammNode: () => true,
183
+ order: undefined,
184
+ market: undefined,
185
+ userAccount: undefined,
186
+ isBaseFilled: () => false,
187
+ haveFilled: false,
188
+ };
189
+ }
@@ -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,8 @@ 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
+ public lastSeenTxSig: string;
28
30
 
29
31
  public constructor(
30
32
  private connection: Connection,
@@ -62,19 +64,22 @@ export class EventSubscriber {
62
64
  }
63
65
  }
64
66
 
65
- public subscribe(): boolean {
66
- if (this.logProvider.isSubscribed()) {
67
- return true;
68
- }
67
+ public async subscribe(): Promise<boolean> {
68
+ try {
69
+ if (this.logProvider.isSubscribed()) {
70
+ return true;
71
+ }
69
72
 
70
- this.fetchPreviousTx().catch((e) => {
73
+ this.logProvider.subscribe((txSig, slot, logs) => {
74
+ this.handleTxLogs(txSig, slot, logs);
75
+ }, true);
76
+
77
+ return true;
78
+ } catch (e) {
71
79
  console.error('Error fetching previous txs in event subscriber');
72
80
  console.error(e);
73
- });
74
-
75
- return this.logProvider.subscribe((txSig, slot, logs) => {
76
- this.handleTxLogs(txSig, slot, logs);
77
- });
81
+ return false;
82
+ }
78
83
  }
79
84
 
80
85
  private handleTxLogs(
@@ -98,11 +103,14 @@ export class EventSubscriber {
98
103
  this.awaitTxResolver.delete(txSig);
99
104
  }
100
105
 
106
+ if (slot > this.lastSeenSlot) {
107
+ this.lastSeenTxSig = txSig;
108
+ }
101
109
  this.txEventCache.add(txSig, wrappedEvents);
102
110
  }
103
111
 
104
- private async fetchPreviousTx(): Promise<void> {
105
- if (!this.options.untilTx) {
112
+ public async fetchPreviousTx(fetchMax?: boolean): Promise<void> {
113
+ if (!this.options.untilTx && !fetchMax) {
106
114
  return;
107
115
  }
108
116
 
@@ -1,14 +1,18 @@
1
+ import { Program } from '@project-serum/anchor';
1
2
  import {
2
3
  Connection,
3
4
  Finality,
4
5
  PublicKey,
5
6
  TransactionSignature,
6
7
  } from '@solana/web3.js';
8
+ import { WrappedEvents } from './types';
7
9
 
8
10
  type Log = { txSig: TransactionSignature; slot: number; logs: string[] };
9
11
  type FetchLogsResponse = {
10
12
  earliestTx: string;
11
13
  mostRecentTx: string;
14
+ earliestSlot: number;
15
+ mostRecentSlot: number;
12
16
  transactionLogs: Log[];
13
17
  };
14
18
 
@@ -17,19 +21,21 @@ export async function fetchLogs(
17
21
  programId: PublicKey,
18
22
  finality: Finality,
19
23
  beforeTx?: TransactionSignature,
20
- untilTx?: TransactionSignature
21
- ): Promise<FetchLogsResponse | undefined> {
24
+ untilTx?: TransactionSignature,
25
+ limit?: number
26
+ ): Promise<FetchLogsResponse> {
22
27
  const signatures = await connection.getSignaturesForAddress(
23
28
  programId,
24
29
  {
25
30
  before: beforeTx,
26
31
  until: untilTx,
32
+ limit,
27
33
  },
28
34
  finality
29
35
  );
30
36
 
31
37
  const sortedSignatures = signatures.sort((a, b) =>
32
- a.slot < b.slot ? -1 : 1
38
+ a.slot === b.slot ? 0 : a.slot < b.slot ? -1 : 1
33
39
  );
34
40
 
35
41
  const filteredSignatures = sortedSignatures.filter(
@@ -61,14 +67,15 @@ export async function fetchLogs(
61
67
  )
62
68
  ).flat();
63
69
 
64
- const earliestTx = filteredSignatures[0].signature;
65
- const mostRecentTx =
66
- filteredSignatures[filteredSignatures.length - 1].signature;
70
+ const earliest = filteredSignatures[0];
71
+ const mostRecent = filteredSignatures[filteredSignatures.length - 1];
67
72
 
68
73
  return {
69
74
  transactionLogs: transactionLogs,
70
- earliestTx: earliestTx,
71
- mostRecentTx: mostRecentTx,
75
+ earliestTx: earliest.signature,
76
+ mostRecentTx: mostRecent.signature,
77
+ earliestSlot: earliest.slot,
78
+ mostRecentSlot: mostRecent.slot,
72
79
  };
73
80
  }
74
81
 
@@ -78,3 +85,23 @@ function chunk<T>(array: readonly T[], size: number): T[][] {
78
85
  .map((_, index) => index * size)
79
86
  .map((begin) => array.slice(begin, begin + size));
80
87
  }
88
+
89
+ export class LogParser {
90
+ private program: Program;
91
+
92
+ constructor(program: Program) {
93
+ this.program = program;
94
+ }
95
+
96
+ public parseEventsFromLogs(event: Log): WrappedEvents {
97
+ const records: WrappedEvents = [];
98
+ // @ts-ignore
99
+ this.program._events._eventParser.parseLogs(event.logs, (eventLog) => {
100
+ eventLog.data.txSig = event.txSig;
101
+ eventLog.data.slot = event.slot;
102
+ eventLog.data.eventType = eventLog.name;
103
+ records.push(eventLog.data);
104
+ });
105
+ return records;
106
+ }
107
+ }
@@ -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
  }
@@ -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
  }