@nadohq/indexer-client 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/IndexerBaseClient.cjs +608 -0
- package/dist/IndexerBaseClient.cjs.map +1 -0
- package/dist/IndexerBaseClient.d.cts +183 -0
- package/dist/IndexerBaseClient.d.ts +183 -0
- package/dist/IndexerBaseClient.js +605 -0
- package/dist/IndexerBaseClient.js.map +1 -0
- package/dist/IndexerClient.cjs +368 -0
- package/dist/IndexerClient.cjs.map +1 -0
- package/dist/IndexerClient.d.cts +50 -0
- package/dist/IndexerClient.d.ts +50 -0
- package/dist/IndexerClient.js +348 -0
- package/dist/IndexerClient.js.map +1 -0
- package/dist/dataMappers.cjs +324 -0
- package/dist/dataMappers.cjs.map +1 -0
- package/dist/dataMappers.d.cts +31 -0
- package/dist/dataMappers.d.ts +31 -0
- package/dist/dataMappers.js +296 -0
- package/dist/dataMappers.js.map +1 -0
- package/dist/endpoints.cjs +35 -0
- package/dist/endpoints.cjs.map +1 -0
- package/dist/endpoints.d.cts +5 -0
- package/dist/endpoints.d.ts +5 -0
- package/dist/endpoints.js +10 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/index.cjs +31 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/types/CandlestickPeriod.cjs +42 -0
- package/dist/types/CandlestickPeriod.cjs.map +1 -0
- package/dist/types/CandlestickPeriod.d.cts +13 -0
- package/dist/types/CandlestickPeriod.d.ts +13 -0
- package/dist/types/CandlestickPeriod.js +17 -0
- package/dist/types/CandlestickPeriod.js.map +1 -0
- package/dist/types/IndexerEventType.cjs +19 -0
- package/dist/types/IndexerEventType.cjs.map +1 -0
- package/dist/types/IndexerEventType.d.cts +3 -0
- package/dist/types/IndexerEventType.d.ts +3 -0
- package/dist/types/IndexerEventType.js +1 -0
- package/dist/types/IndexerEventType.js.map +1 -0
- package/dist/types/IndexerLeaderboardType.cjs +19 -0
- package/dist/types/IndexerLeaderboardType.cjs.map +1 -0
- package/dist/types/IndexerLeaderboardType.d.cts +3 -0
- package/dist/types/IndexerLeaderboardType.d.ts +3 -0
- package/dist/types/IndexerLeaderboardType.js +1 -0
- package/dist/types/IndexerLeaderboardType.js.map +1 -0
- package/dist/types/NadoTx.cjs +19 -0
- package/dist/types/NadoTx.cjs.map +1 -0
- package/dist/types/NadoTx.d.cts +49 -0
- package/dist/types/NadoTx.d.ts +49 -0
- package/dist/types/NadoTx.js +1 -0
- package/dist/types/NadoTx.js.map +1 -0
- package/dist/types/clientTypes.cjs +19 -0
- package/dist/types/clientTypes.cjs.map +1 -0
- package/dist/types/clientTypes.d.cts +467 -0
- package/dist/types/clientTypes.d.ts +467 -0
- package/dist/types/clientTypes.js +1 -0
- package/dist/types/clientTypes.js.map +1 -0
- package/dist/types/collateralEventType.cjs +19 -0
- package/dist/types/collateralEventType.cjs.map +1 -0
- package/dist/types/collateralEventType.d.cts +3 -0
- package/dist/types/collateralEventType.d.ts +3 -0
- package/dist/types/collateralEventType.js +1 -0
- package/dist/types/collateralEventType.js.map +1 -0
- package/dist/types/index.cjs +41 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +13 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/paginatedEventsTypes.cjs +19 -0
- package/dist/types/paginatedEventsTypes.cjs.map +1 -0
- package/dist/types/paginatedEventsTypes.d.cts +115 -0
- package/dist/types/paginatedEventsTypes.d.ts +115 -0
- package/dist/types/paginatedEventsTypes.js +1 -0
- package/dist/types/paginatedEventsTypes.js.map +1 -0
- package/dist/types/serverModelTypes.cjs +19 -0
- package/dist/types/serverModelTypes.cjs.map +1 -0
- package/dist/types/serverModelTypes.d.cts +224 -0
- package/dist/types/serverModelTypes.d.ts +224 -0
- package/dist/types/serverModelTypes.js +1 -0
- package/dist/types/serverModelTypes.js.map +1 -0
- package/dist/types/serverTypes.cjs +19 -0
- package/dist/types/serverTypes.cjs.map +1 -0
- package/dist/types/serverTypes.d.cts +304 -0
- package/dist/types/serverTypes.d.ts +304 -0
- package/dist/types/serverTypes.js +1 -0
- package/dist/types/serverTypes.js.map +1 -0
- package/dist/utils/index.cjs +25 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +12 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/indexerBalanceValue.cjs +43 -0
- package/dist/utils/indexerBalanceValue.cjs.map +1 -0
- package/dist/utils/indexerBalanceValue.d.cts +39 -0
- package/dist/utils/indexerBalanceValue.d.ts +39 -0
- package/dist/utils/indexerBalanceValue.js +16 -0
- package/dist/utils/indexerBalanceValue.js.map +1 -0
- package/package.json +53 -0
- package/src/IndexerBaseClient.ts +851 -0
- package/src/IndexerClient.ts +468 -0
- package/src/dataMappers.ts +362 -0
- package/src/endpoints.ts +7 -0
- package/src/index.ts +4 -0
- package/src/types/CandlestickPeriod.ts +11 -0
- package/src/types/IndexerEventType.ts +9 -0
- package/src/types/IndexerLeaderboardType.ts +2 -0
- package/src/types/NadoTx.ts +63 -0
- package/src/types/clientTypes.ts +679 -0
- package/src/types/collateralEventType.ts +4 -0
- package/src/types/index.ts +9 -0
- package/src/types/paginatedEventsTypes.ts +194 -0
- package/src/types/serverModelTypes.ts +271 -0
- package/src/types/serverTypes.ts +427 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/indexerBalanceValue.ts +46 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProductEngineType,
|
|
3
|
+
QUOTE_PRODUCT_ID,
|
|
4
|
+
subaccountFromHex,
|
|
5
|
+
VLP_PRODUCT_ID,
|
|
6
|
+
} from '@nadohq/contracts';
|
|
7
|
+
import { toBigDecimal, toIntegerString } from '@nadohq/utils';
|
|
8
|
+
|
|
9
|
+
import { IndexerBaseClient } from './IndexerBaseClient';
|
|
10
|
+
import {
|
|
11
|
+
BaseIndexerPaginatedEvent,
|
|
12
|
+
CollateralEventType,
|
|
13
|
+
GetIndexerPaginatedInterestFundingPaymentsResponse,
|
|
14
|
+
GetIndexerPaginatedLeaderboardParams,
|
|
15
|
+
GetIndexerPaginatedLeaderboardResponse,
|
|
16
|
+
GetIndexerPaginatedOrdersParams,
|
|
17
|
+
GetIndexerPaginatedOrdersResponse,
|
|
18
|
+
GetIndexerSubaccountCollateralEventsParams,
|
|
19
|
+
GetIndexerSubaccountCollateralEventsResponse,
|
|
20
|
+
GetIndexerSubaccountInterestFundingPaymentsParams,
|
|
21
|
+
GetIndexerSubaccountLiquidationEventsParams,
|
|
22
|
+
GetIndexerSubaccountLiquidationEventsResponse,
|
|
23
|
+
GetIndexerSubaccountMatchEventParams,
|
|
24
|
+
GetIndexerSubaccountMatchEventsResponse,
|
|
25
|
+
GetIndexerSubaccountSettlementEventsParams,
|
|
26
|
+
GetIndexerSubaccountSettlementEventsResponse,
|
|
27
|
+
GetIndexerSubaccountVlpEventsParams,
|
|
28
|
+
GetIndexerSubaccountVlpEventsResponse,
|
|
29
|
+
IndexerCollateralEvent,
|
|
30
|
+
IndexerEventPerpStateSnapshot,
|
|
31
|
+
IndexerEventSpotStateSnapshot,
|
|
32
|
+
IndexerEventWithTx,
|
|
33
|
+
IndexerLiquidationEvent,
|
|
34
|
+
IndexerSettlementEvent,
|
|
35
|
+
IndexerVlpEvent,
|
|
36
|
+
PaginatedIndexerEventsResponse,
|
|
37
|
+
} from './types';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Indexer client providing paginated queries for historical data from the Nado indexer service
|
|
41
|
+
*/
|
|
42
|
+
export class IndexerClient extends IndexerBaseClient {
|
|
43
|
+
async getPaginatedSubaccountMatchEvents(
|
|
44
|
+
params: GetIndexerSubaccountMatchEventParams,
|
|
45
|
+
): Promise<GetIndexerSubaccountMatchEventsResponse> {
|
|
46
|
+
const {
|
|
47
|
+
startCursor,
|
|
48
|
+
maxTimestampInclusive,
|
|
49
|
+
limit: requestedLimit,
|
|
50
|
+
subaccountName,
|
|
51
|
+
subaccountOwner,
|
|
52
|
+
isolated,
|
|
53
|
+
productIds,
|
|
54
|
+
} = params;
|
|
55
|
+
|
|
56
|
+
const limit = requestedLimit + 1;
|
|
57
|
+
const events = await this.getMatchEvents({
|
|
58
|
+
startCursor,
|
|
59
|
+
maxTimestampInclusive,
|
|
60
|
+
limit,
|
|
61
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
62
|
+
productIds,
|
|
63
|
+
isolated,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return this.getPaginationEventsResponse(events, requestedLimit);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async getPaginatedSubaccountVlpEvents(
|
|
70
|
+
params: GetIndexerSubaccountVlpEventsParams,
|
|
71
|
+
): Promise<GetIndexerSubaccountVlpEventsResponse> {
|
|
72
|
+
const {
|
|
73
|
+
startCursor,
|
|
74
|
+
maxTimestampInclusive,
|
|
75
|
+
limit: requestedLimit,
|
|
76
|
+
subaccountName,
|
|
77
|
+
subaccountOwner,
|
|
78
|
+
} = params;
|
|
79
|
+
|
|
80
|
+
// There are 2 events per mint/burn for spot - one associated with the VLP product & the other with the primary quote
|
|
81
|
+
const limit = requestedLimit + 1;
|
|
82
|
+
const baseResponse = await this.getEvents({
|
|
83
|
+
startCursor,
|
|
84
|
+
maxTimestampInclusive,
|
|
85
|
+
eventTypes: ['mint_vlp', 'burn_vlp'],
|
|
86
|
+
limit: {
|
|
87
|
+
type: 'txs',
|
|
88
|
+
value: limit,
|
|
89
|
+
},
|
|
90
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Now aggregate results by the submission index, use map to maintain insertion order
|
|
94
|
+
const eventsBySubmissionIdx = new Map<string, IndexerVlpEvent>();
|
|
95
|
+
|
|
96
|
+
baseResponse.forEach((event) => {
|
|
97
|
+
const mappedEvent = (() => {
|
|
98
|
+
const existingEvent = eventsBySubmissionIdx.get(event.submissionIndex);
|
|
99
|
+
if (existingEvent) {
|
|
100
|
+
return existingEvent;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const newEvent: IndexerVlpEvent = {
|
|
104
|
+
vlpDelta: toBigDecimal(0),
|
|
105
|
+
primaryQuoteDelta: toBigDecimal(0),
|
|
106
|
+
timestamp: event.timestamp,
|
|
107
|
+
submissionIndex: event.submissionIndex,
|
|
108
|
+
tx: event.tx,
|
|
109
|
+
...subaccountFromHex(event.subaccount),
|
|
110
|
+
};
|
|
111
|
+
eventsBySubmissionIdx.set(event.submissionIndex, newEvent);
|
|
112
|
+
|
|
113
|
+
return newEvent;
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
const balanceDelta = event.state.postBalance.amount.minus(
|
|
117
|
+
event.state.preBalance.amount,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const productId = event.state.market.productId;
|
|
121
|
+
if (productId === QUOTE_PRODUCT_ID) {
|
|
122
|
+
mappedEvent.primaryQuoteDelta = balanceDelta;
|
|
123
|
+
} else if (productId === VLP_PRODUCT_ID) {
|
|
124
|
+
mappedEvent.vlpDelta = balanceDelta;
|
|
125
|
+
} else {
|
|
126
|
+
throw Error(`Invalid product ID for VLP event ${productId}`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Force cast to get rid of the `Partial`
|
|
131
|
+
const events = Array.from(eventsBySubmissionIdx.values());
|
|
132
|
+
return this.getPaginationEventsResponse(events, requestedLimit);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async getPaginatedSubaccountCollateralEvents(
|
|
136
|
+
params: GetIndexerSubaccountCollateralEventsParams,
|
|
137
|
+
): Promise<GetIndexerSubaccountCollateralEventsResponse> {
|
|
138
|
+
const {
|
|
139
|
+
startCursor,
|
|
140
|
+
maxTimestampInclusive,
|
|
141
|
+
limit: requestedLimit,
|
|
142
|
+
subaccountName,
|
|
143
|
+
subaccountOwner,
|
|
144
|
+
eventTypes,
|
|
145
|
+
isolated,
|
|
146
|
+
} = params;
|
|
147
|
+
|
|
148
|
+
const limit = requestedLimit + 1;
|
|
149
|
+
const baseResponse = await this.getEvents({
|
|
150
|
+
startCursor,
|
|
151
|
+
maxTimestampInclusive,
|
|
152
|
+
eventTypes: eventTypes ?? [
|
|
153
|
+
'deposit_collateral',
|
|
154
|
+
'withdraw_collateral',
|
|
155
|
+
'transfer_quote',
|
|
156
|
+
],
|
|
157
|
+
limit: {
|
|
158
|
+
type: 'txs',
|
|
159
|
+
value: limit,
|
|
160
|
+
},
|
|
161
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
162
|
+
isolated,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const events = baseResponse.map((event): IndexerCollateralEvent => {
|
|
166
|
+
if (event.state.type !== ProductEngineType.SPOT) {
|
|
167
|
+
throw Error('Incorrect event state for collateral event');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
timestamp: event.timestamp,
|
|
172
|
+
// This cast is safe as the query param restricts to collateral events
|
|
173
|
+
eventType: event.eventType as CollateralEventType,
|
|
174
|
+
submissionIndex: event.submissionIndex,
|
|
175
|
+
snapshot: event.state,
|
|
176
|
+
amount: event.state.postBalance.amount.minus(
|
|
177
|
+
event.state.preBalance.amount,
|
|
178
|
+
),
|
|
179
|
+
newAmount: event.state.postBalance.amount,
|
|
180
|
+
tx: event.tx,
|
|
181
|
+
...subaccountFromHex(event.subaccount),
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return this.getPaginationEventsResponse(events, requestedLimit);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async getPaginatedSubaccountOrders(
|
|
189
|
+
params: GetIndexerPaginatedOrdersParams,
|
|
190
|
+
): Promise<GetIndexerPaginatedOrdersResponse> {
|
|
191
|
+
const {
|
|
192
|
+
startCursor,
|
|
193
|
+
maxTimestampInclusive,
|
|
194
|
+
limit: requestedLimit,
|
|
195
|
+
subaccountName,
|
|
196
|
+
subaccountOwner,
|
|
197
|
+
productIds,
|
|
198
|
+
isolated,
|
|
199
|
+
} = params;
|
|
200
|
+
|
|
201
|
+
const limit = requestedLimit + 1;
|
|
202
|
+
const baseResponse = await this.getOrders({
|
|
203
|
+
startCursor,
|
|
204
|
+
maxTimestampInclusive,
|
|
205
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
206
|
+
limit,
|
|
207
|
+
productIds,
|
|
208
|
+
isolated,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Same pagination meta logic as events, but duplicate for now as this return type is slightly different
|
|
212
|
+
const truncatedOrders = baseResponse.slice(0, requestedLimit);
|
|
213
|
+
const hasMore = baseResponse.length > truncatedOrders.length;
|
|
214
|
+
return {
|
|
215
|
+
meta: {
|
|
216
|
+
hasMore,
|
|
217
|
+
nextCursor: baseResponse[truncatedOrders.length]?.submissionIndex,
|
|
218
|
+
},
|
|
219
|
+
orders: truncatedOrders,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async getPaginatedSubaccountSettlementEvents(
|
|
224
|
+
params: GetIndexerSubaccountSettlementEventsParams,
|
|
225
|
+
): Promise<GetIndexerSubaccountSettlementEventsResponse> {
|
|
226
|
+
const {
|
|
227
|
+
startCursor,
|
|
228
|
+
maxTimestampInclusive,
|
|
229
|
+
limit: requestedLimit,
|
|
230
|
+
subaccountName,
|
|
231
|
+
subaccountOwner,
|
|
232
|
+
} = params;
|
|
233
|
+
|
|
234
|
+
// Each settlement has a quote & perp balance change, so 2 events per settlement tx
|
|
235
|
+
const limit = requestedLimit + 1;
|
|
236
|
+
const baseResponse = await this.getEvents({
|
|
237
|
+
startCursor,
|
|
238
|
+
maxTimestampInclusive,
|
|
239
|
+
eventTypes: ['settle_pnl'],
|
|
240
|
+
limit: {
|
|
241
|
+
type: 'txs',
|
|
242
|
+
value: limit,
|
|
243
|
+
},
|
|
244
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const events = baseResponse
|
|
248
|
+
.map((event): IndexerSettlementEvent | undefined => {
|
|
249
|
+
if (event.state.market.productId === QUOTE_PRODUCT_ID) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (event.state.type !== ProductEngineType.PERP) {
|
|
253
|
+
throw Error('Incorrect event state for settlement event');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
timestamp: event.timestamp,
|
|
258
|
+
submissionIndex: event.submissionIndex,
|
|
259
|
+
snapshot: event.state,
|
|
260
|
+
// Spot quote delta = -vQuote delta
|
|
261
|
+
quoteDelta: event.state.preBalance.vQuoteBalance.minus(
|
|
262
|
+
event.state.postBalance.vQuoteBalance,
|
|
263
|
+
),
|
|
264
|
+
isolated: event.isolated,
|
|
265
|
+
tx: event.tx,
|
|
266
|
+
...subaccountFromHex(event.subaccount),
|
|
267
|
+
};
|
|
268
|
+
})
|
|
269
|
+
.filter((event): event is IndexerSettlementEvent => !!event);
|
|
270
|
+
|
|
271
|
+
return this.getPaginationEventsResponse(events, requestedLimit);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async getPaginatedSubaccountLiquidationEvents(
|
|
275
|
+
params: GetIndexerSubaccountLiquidationEventsParams,
|
|
276
|
+
): Promise<GetIndexerSubaccountLiquidationEventsResponse> {
|
|
277
|
+
const {
|
|
278
|
+
startCursor,
|
|
279
|
+
maxTimestampInclusive,
|
|
280
|
+
limit: requestedLimit,
|
|
281
|
+
subaccountName,
|
|
282
|
+
subaccountOwner,
|
|
283
|
+
} = params;
|
|
284
|
+
|
|
285
|
+
// There is 1 event emitted per product, including quote
|
|
286
|
+
// However, if the balance change is 0, then the liquidation did not touch the product
|
|
287
|
+
// A tx operates on a given health group, so only a spot & its associated perp can be actually liquidated within a single tx
|
|
288
|
+
// with an associated quote balance change
|
|
289
|
+
const limit = requestedLimit + 1;
|
|
290
|
+
const baseResponse = await this.getEvents({
|
|
291
|
+
startCursor,
|
|
292
|
+
maxTimestampInclusive,
|
|
293
|
+
eventTypes: ['liquidate_subaccount'],
|
|
294
|
+
limit: {
|
|
295
|
+
type: 'txs',
|
|
296
|
+
value: limit,
|
|
297
|
+
},
|
|
298
|
+
subaccount: { subaccountName, subaccountOwner },
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Now aggregate results by the submission index, use map to maintain insertion order
|
|
302
|
+
const eventsBySubmissionIdx = new Map<
|
|
303
|
+
string,
|
|
304
|
+
Partial<IndexerLiquidationEvent>
|
|
305
|
+
>();
|
|
306
|
+
|
|
307
|
+
baseResponse.forEach((event) => {
|
|
308
|
+
const mappedEvent = (() => {
|
|
309
|
+
const existingEvent = eventsBySubmissionIdx.get(event.submissionIndex);
|
|
310
|
+
if (existingEvent) {
|
|
311
|
+
return existingEvent;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const newEvent: Partial<IndexerLiquidationEvent> = {
|
|
315
|
+
perp: undefined,
|
|
316
|
+
spot: undefined,
|
|
317
|
+
quote: undefined,
|
|
318
|
+
timestamp: event.timestamp,
|
|
319
|
+
submissionIndex: event.submissionIndex,
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
return newEvent;
|
|
323
|
+
})();
|
|
324
|
+
|
|
325
|
+
// The original balance is the negated delta
|
|
326
|
+
const balanceDelta = event.state.postBalance.amount.minus(
|
|
327
|
+
event.state.preBalance.amount,
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
// Event without balance change - not part of this liq
|
|
331
|
+
// However, we could have zero balance changes for the quote product if this was a partial liquidation
|
|
332
|
+
if (
|
|
333
|
+
balanceDelta.isZero() &&
|
|
334
|
+
event.state.market.productId !== QUOTE_PRODUCT_ID
|
|
335
|
+
) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (event.state.type === ProductEngineType.PERP) {
|
|
340
|
+
mappedEvent.perp = {
|
|
341
|
+
amountLiquidated: balanceDelta.negated(),
|
|
342
|
+
// This cast is safe because we're checking for event.state.type
|
|
343
|
+
indexerEvent:
|
|
344
|
+
event as IndexerEventWithTx<IndexerEventPerpStateSnapshot>,
|
|
345
|
+
};
|
|
346
|
+
} else if (event.state.market.productId === QUOTE_PRODUCT_ID) {
|
|
347
|
+
mappedEvent.quote = {
|
|
348
|
+
balanceDelta,
|
|
349
|
+
indexerEvent:
|
|
350
|
+
event as IndexerEventWithTx<IndexerEventSpotStateSnapshot>,
|
|
351
|
+
};
|
|
352
|
+
} else {
|
|
353
|
+
mappedEvent.spot = {
|
|
354
|
+
amountLiquidated: balanceDelta.negated(),
|
|
355
|
+
indexerEvent:
|
|
356
|
+
event as IndexerEventWithTx<IndexerEventSpotStateSnapshot>,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
eventsBySubmissionIdx.set(event.submissionIndex, mappedEvent);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Force cast to get rid of the `Partial`
|
|
364
|
+
const events = Array.from(
|
|
365
|
+
eventsBySubmissionIdx.values(),
|
|
366
|
+
) as IndexerLiquidationEvent[];
|
|
367
|
+
return this.getPaginationEventsResponse(events, requestedLimit);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get all interest funding payments for a given subaccount with the standard pagination response
|
|
372
|
+
* This is a simple wrapper over the underlying `getInterestFundingPayments` function. Very little
|
|
373
|
+
* additional processing is needed because the endpoint is well structured for pagination
|
|
374
|
+
*
|
|
375
|
+
* @param params
|
|
376
|
+
*/
|
|
377
|
+
async getPaginatedSubaccountInterestFundingPayments(
|
|
378
|
+
params: GetIndexerSubaccountInterestFundingPaymentsParams,
|
|
379
|
+
): Promise<GetIndexerPaginatedInterestFundingPaymentsResponse> {
|
|
380
|
+
const {
|
|
381
|
+
limit,
|
|
382
|
+
productIds,
|
|
383
|
+
startCursor,
|
|
384
|
+
maxTimestampInclusive,
|
|
385
|
+
subaccountName,
|
|
386
|
+
subaccountOwner,
|
|
387
|
+
} = params;
|
|
388
|
+
const baseResponse = await this.getInterestFundingPayments({
|
|
389
|
+
limit,
|
|
390
|
+
productIds,
|
|
391
|
+
startCursor,
|
|
392
|
+
maxTimestampInclusive,
|
|
393
|
+
subaccount: {
|
|
394
|
+
subaccountName,
|
|
395
|
+
subaccountOwner,
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
...baseResponse,
|
|
401
|
+
meta: {
|
|
402
|
+
hasMore: baseResponse.nextCursor != null,
|
|
403
|
+
nextCursor: baseResponse.nextCursor ?? undefined,
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Paginated leaderboard query that paginates on rank number.
|
|
410
|
+
*
|
|
411
|
+
* @param params
|
|
412
|
+
*/
|
|
413
|
+
async getPaginatedLeaderboard(
|
|
414
|
+
params: GetIndexerPaginatedLeaderboardParams,
|
|
415
|
+
): Promise<GetIndexerPaginatedLeaderboardResponse> {
|
|
416
|
+
const requestedLimit = params.limit;
|
|
417
|
+
|
|
418
|
+
const baseResponse = await this.getLeaderboard({
|
|
419
|
+
contestId: params.contestId,
|
|
420
|
+
rankType: params.rankType,
|
|
421
|
+
// Query for 1 more result for proper pagination
|
|
422
|
+
limit: requestedLimit + 1,
|
|
423
|
+
// Start cursor is the next rank number
|
|
424
|
+
startCursor: params.startCursor,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Next cursor is the rank number of the (requestedLimit+1)th item
|
|
428
|
+
const nextCursor =
|
|
429
|
+
params.rankType === 'pnl'
|
|
430
|
+
? baseResponse.participants[requestedLimit]?.pnlRank
|
|
431
|
+
: baseResponse.participants[requestedLimit]?.roiRank;
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
...baseResponse,
|
|
435
|
+
// Truncate the response to the requested limit
|
|
436
|
+
participants: baseResponse.participants.slice(0, requestedLimit),
|
|
437
|
+
meta: {
|
|
438
|
+
hasMore: baseResponse.participants.length > requestedLimit,
|
|
439
|
+
nextCursor:
|
|
440
|
+
nextCursor !== undefined ? toIntegerString(nextCursor) : undefined,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* A util function to generate the standard pagination response for events
|
|
447
|
+
* @param events
|
|
448
|
+
* @param requestedLimit given by consumers of the SDK
|
|
449
|
+
* @private
|
|
450
|
+
*/
|
|
451
|
+
private getPaginationEventsResponse<T extends BaseIndexerPaginatedEvent>(
|
|
452
|
+
events: T[],
|
|
453
|
+
requestedLimit: number,
|
|
454
|
+
): PaginatedIndexerEventsResponse<T> {
|
|
455
|
+
const truncatedEvents = events.slice(0, requestedLimit);
|
|
456
|
+
const hasMore = events.length > truncatedEvents.length;
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
events: truncatedEvents,
|
|
460
|
+
meta: {
|
|
461
|
+
hasMore,
|
|
462
|
+
// We want the NEXT available cursor, so we use the first event after the truncation cutoff
|
|
463
|
+
// If len(events) === len(truncatedEvents), there are no more entries and this is undefined
|
|
464
|
+
nextCursor: events[truncatedEvents.length]?.submissionIndex,
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
}
|