@morpho-dev/router 0.1.18 → 0.2.0
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 +28 -18
- package/dist/cli.js +3020 -2174
- package/dist/cli.js.map +1 -1
- package/dist/drizzle/VERSION.ts +3 -0
- package/dist/drizzle/drizzle.config.ts +18 -0
- package/dist/drizzle/index.ts +2 -0
- package/dist/drizzle/{router_v1.4/0000_add_obligation_id.sql → router_v1.5/0000_add_block_number_to_liquidity_graph_and_offer_liquidity_pools_relation.sql} +49 -39
- package/dist/drizzle/router_v1.5/0001_create_new_relations_to_prepare_new_liquidity_model.sql +55 -0
- package/dist/drizzle/router_v1.5/0002_add_new_offer_status_relation.sql +9 -0
- package/dist/drizzle/router_v1.5/0003_insert-status-code.sql +1 -0
- package/dist/drizzle/router_v1.5/0004_add_index_for_fast_book_lookup.sql +3 -0
- package/dist/drizzle/router_v1.5/0005_add_group_consumed_events_table.sql +12 -0
- package/dist/drizzle/router_v1.5/0006_add-trigger-for-consumed-events.sql +58 -0
- package/dist/drizzle/router_v1.5/0007_update_index_for_fast_book_lookup.sql +5 -0
- package/dist/drizzle/router_v1.5/0008_rename_consumed_events_table.sql +8 -0
- package/dist/drizzle/{router_v1.4 → router_v1.5}/meta/0000_snapshot.json +83 -27
- package/dist/drizzle/{router_v1.4 → router_v1.5}/meta/0001_snapshot.json +459 -27
- package/dist/drizzle/router_v1.5/meta/0002_snapshot.json +1463 -0
- package/dist/drizzle/router_v1.5/meta/0003_snapshot.json +1463 -0
- package/dist/drizzle/router_v1.5/meta/0004_snapshot.json +1569 -0
- package/dist/drizzle/router_v1.5/meta/0005_snapshot.json +1664 -0
- package/dist/drizzle/router_v1.5/meta/0006_snapshot.json +1664 -0
- package/dist/drizzle/router_v1.5/meta/0007_snapshot.json +1752 -0
- package/dist/drizzle/router_v1.5/meta/0008_snapshot.json +1752 -0
- package/dist/drizzle/router_v1.5/meta/_journal.json +69 -0
- package/dist/drizzle/schema.ts +363 -0
- package/dist/index.browser.d.cts +884 -156
- package/dist/index.browser.d.ts +884 -156
- package/dist/index.browser.js +1433 -1010
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +1426 -1009
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +2578 -930
- package/dist/index.node.d.ts +2578 -930
- package/dist/index.node.js +6544 -5459
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +6769 -5688
- package/dist/index.node.mjs.map +1 -1
- package/package.json +17 -13
- package/dist/drizzle/router_v1.4/0001_update-primary-key-on-link.sql +0 -3
- package/dist/drizzle/router_v1.4/meta/_journal.json +0 -20
package/dist/index.browser.mjs
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
|
-
import { maxUint256, isAddress, isHex,
|
|
3
|
-
import
|
|
2
|
+
import { maxUint256, isAddress, isHex, decodeAbiParameters, encodeAbiParameters, keccak256, zeroAddress, bytesToHex, hexToBytes, hashTypedData, getAddress, publicActions } from 'viem';
|
|
3
|
+
import 'reflect-metadata';
|
|
4
|
+
import { generateDocument } from 'openapi-metadata';
|
|
5
|
+
import { ApiProperty, ApiOperation, ApiQuery, ApiResponse, ApiTags } from 'openapi-metadata/decorators';
|
|
6
|
+
import * as z9 from 'zod';
|
|
7
|
+
import { Base64 } from 'js-base64';
|
|
8
|
+
import createOpenApiFetchClient from 'openapi-fetch';
|
|
4
9
|
import { getBlock, getLogs } from 'viem/actions';
|
|
5
10
|
import { base, mainnet, anvil } from 'viem/chains';
|
|
6
|
-
import * as z7 from 'zod';
|
|
7
11
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
8
|
-
import {
|
|
12
|
+
import { StandardMerkleTree } from '@openzeppelin/merkle-tree';
|
|
13
|
+
import { gzip, ungzip } from 'pako';
|
|
9
14
|
|
|
10
15
|
var __defProp = Object.defineProperty;
|
|
16
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
17
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
12
18
|
var __export = (target, all) => {
|
|
13
19
|
for (var name in all)
|
|
14
20
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
21
|
};
|
|
22
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
23
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
24
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
25
|
+
if (decorator = decorators[i])
|
|
26
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
27
|
+
if (kind && result) __defProp(target, key, result);
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
16
30
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
17
31
|
|
|
18
32
|
// src/api/Schema/index.ts
|
|
@@ -22,8 +36,11 @@ __export(Schema_exports, {
|
|
|
22
36
|
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
23
37
|
CollectorHealth: () => CollectorHealth,
|
|
24
38
|
CollectorsHealthResponse: () => CollectorsHealthResponse,
|
|
39
|
+
HealthController: () => HealthController,
|
|
25
40
|
ObligationResponse: () => ObligationResponse_exports,
|
|
41
|
+
ObligationsController: () => ObligationsController,
|
|
26
42
|
OfferResponse: () => OfferResponse_exports,
|
|
43
|
+
OffersController: () => OffersController,
|
|
27
44
|
OpenApi: () => OpenApi,
|
|
28
45
|
RouterStatusResponse: () => RouterStatusResponse,
|
|
29
46
|
parse: () => parse,
|
|
@@ -58,6 +75,7 @@ __export(ObligationResponse_exports, {
|
|
|
58
75
|
var Format_exports = {};
|
|
59
76
|
__export(Format_exports, {
|
|
60
77
|
fromSnakeCase: () => fromSnakeCase,
|
|
78
|
+
stringifyBigint: () => stringifyBigint,
|
|
61
79
|
toSnakeCase: () => toSnakeCase
|
|
62
80
|
});
|
|
63
81
|
function toSnakeCase(obj) {
|
|
@@ -117,9 +135,621 @@ __export(OfferResponse_exports, {
|
|
|
117
135
|
from: () => from2
|
|
118
136
|
});
|
|
119
137
|
function from2(offer) {
|
|
120
|
-
|
|
138
|
+
const result = toSnakeCase(offer);
|
|
139
|
+
return { ...result, signature: result.signature ?? null };
|
|
140
|
+
}
|
|
141
|
+
var API_ERROR_CODES = [
|
|
142
|
+
"VALIDATION_ERROR",
|
|
143
|
+
"NOT_FOUND",
|
|
144
|
+
"INTERNAL_SERVER_ERROR",
|
|
145
|
+
"BAD_REQUEST"
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// src/api/Schema/openapi.ts
|
|
149
|
+
var timestampExample = "2024-01-01T12:00:00.000Z";
|
|
150
|
+
var offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
151
|
+
var obligationCursorExample = "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc";
|
|
152
|
+
var offerExample = {
|
|
153
|
+
hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
|
|
154
|
+
offering: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
155
|
+
assets: "369216000000000000000000",
|
|
156
|
+
rate: "2750000000000000000",
|
|
157
|
+
maturity: 1761922799,
|
|
158
|
+
expiry: 1761922799,
|
|
159
|
+
start: 1761922790,
|
|
160
|
+
nonce: "571380",
|
|
161
|
+
buy: false,
|
|
162
|
+
chain_id: "1",
|
|
163
|
+
loan_token: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
164
|
+
collaterals: [
|
|
165
|
+
{
|
|
166
|
+
asset: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
|
|
167
|
+
oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
168
|
+
lltv: "860000000000000000"
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
callback: {
|
|
172
|
+
address: "0x1111111111111111111111111111111111111111",
|
|
173
|
+
data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000",
|
|
174
|
+
gas_limit: "500000"
|
|
175
|
+
},
|
|
176
|
+
signature: "0x1234567890123456789012345678901234567890123456789012345678901234123456789012345678901234567890123456789012345678901234567890123400",
|
|
177
|
+
consumed: "0",
|
|
178
|
+
block_number: 2942933377146801
|
|
179
|
+
};
|
|
180
|
+
var collectorsHealthExample = {
|
|
181
|
+
name: "mempool_offers",
|
|
182
|
+
chain_id: "1",
|
|
183
|
+
block_number: 21345678,
|
|
184
|
+
updated_at: timestampExample,
|
|
185
|
+
lag: 0,
|
|
186
|
+
status: "live"
|
|
187
|
+
};
|
|
188
|
+
var chainsHealthExample = {
|
|
189
|
+
chain_id: "1",
|
|
190
|
+
block_number: 21345678,
|
|
191
|
+
updated_at: timestampExample
|
|
192
|
+
};
|
|
193
|
+
var routerStatusExample = {
|
|
194
|
+
status: "live"
|
|
195
|
+
};
|
|
196
|
+
var Meta = class {
|
|
197
|
+
};
|
|
198
|
+
__decorateClass([
|
|
199
|
+
ApiProperty({ type: "string", example: timestampExample })
|
|
200
|
+
], Meta.prototype, "timestamp", 2);
|
|
201
|
+
var SuccessResponse = class {
|
|
202
|
+
};
|
|
203
|
+
__decorateClass([
|
|
204
|
+
ApiProperty({ type: "string", enum: ["success"] })
|
|
205
|
+
], SuccessResponse.prototype, "status", 2);
|
|
206
|
+
__decorateClass([
|
|
207
|
+
ApiProperty({ type: () => Meta })
|
|
208
|
+
], SuccessResponse.prototype, "meta", 2);
|
|
209
|
+
var ErrorResponse = class {
|
|
210
|
+
};
|
|
211
|
+
__decorateClass([
|
|
212
|
+
ApiProperty({ type: "string", enum: API_ERROR_CODES, example: "VALIDATION_ERROR" })
|
|
213
|
+
], ErrorResponse.prototype, "code", 2);
|
|
214
|
+
__decorateClass([
|
|
215
|
+
ApiProperty({
|
|
216
|
+
type: "string",
|
|
217
|
+
example: "Limit must be greater than 0."
|
|
218
|
+
})
|
|
219
|
+
], ErrorResponse.prototype, "message", 2);
|
|
220
|
+
__decorateClass([
|
|
221
|
+
ApiProperty({
|
|
222
|
+
type: "object",
|
|
223
|
+
example: [
|
|
224
|
+
{
|
|
225
|
+
field: "limit",
|
|
226
|
+
issue: "Limit must be greater than 0."
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
})
|
|
230
|
+
], ErrorResponse.prototype, "details", 2);
|
|
231
|
+
var BadRequestResponse = class {
|
|
232
|
+
};
|
|
233
|
+
__decorateClass([
|
|
234
|
+
ApiProperty({ type: "string", enum: ["error"] })
|
|
235
|
+
], BadRequestResponse.prototype, "status", 2);
|
|
236
|
+
__decorateClass([
|
|
237
|
+
ApiProperty({ type: () => ErrorResponse })
|
|
238
|
+
], BadRequestResponse.prototype, "error", 2);
|
|
239
|
+
__decorateClass([
|
|
240
|
+
ApiProperty({ type: () => Meta })
|
|
241
|
+
], BadRequestResponse.prototype, "meta", 2);
|
|
242
|
+
var CollateralResponse = class {
|
|
243
|
+
};
|
|
244
|
+
__decorateClass([
|
|
245
|
+
ApiProperty({ type: "string", example: "0x34Cf890dB685FC536E05652FB41f02090c3fb751" })
|
|
246
|
+
], CollateralResponse.prototype, "asset", 2);
|
|
247
|
+
__decorateClass([
|
|
248
|
+
ApiProperty({ type: "string", example: "0x45093658BE7f90B63D7c359e8f408e503c2D9401" })
|
|
249
|
+
], CollateralResponse.prototype, "oracle", 2);
|
|
250
|
+
__decorateClass([
|
|
251
|
+
ApiProperty({ type: "string", example: "860000000000000000" })
|
|
252
|
+
], CollateralResponse.prototype, "lltv", 2);
|
|
253
|
+
var AskResponse = class {
|
|
254
|
+
};
|
|
255
|
+
__decorateClass([
|
|
256
|
+
ApiProperty({ type: "string", example: "1000000000000000000" })
|
|
257
|
+
], AskResponse.prototype, "rate", 2);
|
|
258
|
+
var BidResponse = class {
|
|
259
|
+
};
|
|
260
|
+
__decorateClass([
|
|
261
|
+
ApiProperty({ type: "string", example: "1000000000000000000" })
|
|
262
|
+
], BidResponse.prototype, "rate", 2);
|
|
263
|
+
var OfferCallbackResponse = class {
|
|
264
|
+
};
|
|
265
|
+
__decorateClass([
|
|
266
|
+
ApiProperty({ type: "string", example: offerExample.callback.address })
|
|
267
|
+
], OfferCallbackResponse.prototype, "address", 2);
|
|
268
|
+
__decorateClass([
|
|
269
|
+
ApiProperty({ type: "string", example: offerExample.callback.data })
|
|
270
|
+
], OfferCallbackResponse.prototype, "data", 2);
|
|
271
|
+
__decorateClass([
|
|
272
|
+
ApiProperty({ type: "string", example: offerExample.callback.gas_limit })
|
|
273
|
+
], OfferCallbackResponse.prototype, "gas_limit", 2);
|
|
274
|
+
var OfferListItemResponse = class {
|
|
275
|
+
};
|
|
276
|
+
__decorateClass([
|
|
277
|
+
ApiProperty({ type: "string", example: offerExample.hash })
|
|
278
|
+
], OfferListItemResponse.prototype, "hash", 2);
|
|
279
|
+
__decorateClass([
|
|
280
|
+
ApiProperty({ type: "string", example: offerExample.offering })
|
|
281
|
+
], OfferListItemResponse.prototype, "offering", 2);
|
|
282
|
+
__decorateClass([
|
|
283
|
+
ApiProperty({ type: "string", example: offerExample.assets })
|
|
284
|
+
], OfferListItemResponse.prototype, "assets", 2);
|
|
285
|
+
__decorateClass([
|
|
286
|
+
ApiProperty({ type: "string", example: offerExample.rate })
|
|
287
|
+
], OfferListItemResponse.prototype, "rate", 2);
|
|
288
|
+
__decorateClass([
|
|
289
|
+
ApiProperty({ type: "number", example: offerExample.maturity })
|
|
290
|
+
], OfferListItemResponse.prototype, "maturity", 2);
|
|
291
|
+
__decorateClass([
|
|
292
|
+
ApiProperty({ type: "number", example: offerExample.expiry })
|
|
293
|
+
], OfferListItemResponse.prototype, "expiry", 2);
|
|
294
|
+
__decorateClass([
|
|
295
|
+
ApiProperty({ type: "number", example: offerExample.start })
|
|
296
|
+
], OfferListItemResponse.prototype, "start", 2);
|
|
297
|
+
__decorateClass([
|
|
298
|
+
ApiProperty({ type: "string", example: offerExample.nonce })
|
|
299
|
+
], OfferListItemResponse.prototype, "nonce", 2);
|
|
300
|
+
__decorateClass([
|
|
301
|
+
ApiProperty({ type: "boolean", example: offerExample.buy })
|
|
302
|
+
], OfferListItemResponse.prototype, "buy", 2);
|
|
303
|
+
__decorateClass([
|
|
304
|
+
ApiProperty({ type: "string", example: offerExample.chain_id })
|
|
305
|
+
], OfferListItemResponse.prototype, "chain_id", 2);
|
|
306
|
+
__decorateClass([
|
|
307
|
+
ApiProperty({ type: "string", example: offerExample.loan_token })
|
|
308
|
+
], OfferListItemResponse.prototype, "loan_token", 2);
|
|
309
|
+
__decorateClass([
|
|
310
|
+
ApiProperty({ type: () => [CollateralResponse], example: offerExample.collaterals })
|
|
311
|
+
], OfferListItemResponse.prototype, "collaterals", 2);
|
|
312
|
+
__decorateClass([
|
|
313
|
+
ApiProperty({ type: () => OfferCallbackResponse, example: offerExample.callback })
|
|
314
|
+
], OfferListItemResponse.prototype, "callback", 2);
|
|
315
|
+
__decorateClass([
|
|
316
|
+
ApiProperty({ type: "string", example: offerExample.consumed })
|
|
317
|
+
], OfferListItemResponse.prototype, "consumed", 2);
|
|
318
|
+
__decorateClass([
|
|
319
|
+
ApiProperty({ type: "number", example: offerExample.block_number })
|
|
320
|
+
], OfferListItemResponse.prototype, "block_number", 2);
|
|
321
|
+
__decorateClass([
|
|
322
|
+
ApiProperty({ type: "string", nullable: true, example: offerExample.signature })
|
|
323
|
+
], OfferListItemResponse.prototype, "signature", 2);
|
|
324
|
+
var ObligationResponse = class {
|
|
325
|
+
};
|
|
326
|
+
__decorateClass([
|
|
327
|
+
ApiProperty({
|
|
328
|
+
type: "string",
|
|
329
|
+
example: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67"
|
|
330
|
+
})
|
|
331
|
+
], ObligationResponse.prototype, "id", 2);
|
|
332
|
+
__decorateClass([
|
|
333
|
+
ApiProperty({ type: "string", example: "1" })
|
|
334
|
+
], ObligationResponse.prototype, "chain_id", 2);
|
|
335
|
+
__decorateClass([
|
|
336
|
+
ApiProperty({ type: "string", example: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078" })
|
|
337
|
+
], ObligationResponse.prototype, "loan_token", 2);
|
|
338
|
+
__decorateClass([
|
|
339
|
+
ApiProperty({ type: () => [CollateralResponse] })
|
|
340
|
+
], ObligationResponse.prototype, "collaterals", 2);
|
|
341
|
+
__decorateClass([
|
|
342
|
+
ApiProperty({ type: "number", example: 1761922800 })
|
|
343
|
+
], ObligationResponse.prototype, "maturity", 2);
|
|
344
|
+
__decorateClass([
|
|
345
|
+
ApiProperty({ type: () => AskResponse })
|
|
346
|
+
], ObligationResponse.prototype, "ask", 2);
|
|
347
|
+
__decorateClass([
|
|
348
|
+
ApiProperty({ type: () => BidResponse })
|
|
349
|
+
], ObligationResponse.prototype, "bid", 2);
|
|
350
|
+
var ObligationListResponse = class extends SuccessResponse {
|
|
351
|
+
};
|
|
352
|
+
__decorateClass([
|
|
353
|
+
ApiProperty({ type: "string", nullable: true, example: obligationCursorExample })
|
|
354
|
+
], ObligationListResponse.prototype, "cursor", 2);
|
|
355
|
+
__decorateClass([
|
|
356
|
+
ApiProperty({
|
|
357
|
+
type: () => [ObligationResponse],
|
|
358
|
+
description: "List of obligations with takable offers."
|
|
359
|
+
})
|
|
360
|
+
], ObligationListResponse.prototype, "data", 2);
|
|
361
|
+
var ObligationSingleSuccessResponse = class extends SuccessResponse {
|
|
362
|
+
};
|
|
363
|
+
__decorateClass([
|
|
364
|
+
ApiProperty({ type: "string", nullable: true, example: null })
|
|
365
|
+
], ObligationSingleSuccessResponse.prototype, "cursor", 2);
|
|
366
|
+
__decorateClass([
|
|
367
|
+
ApiProperty({ type: () => ObligationResponse, description: "Obligation details." })
|
|
368
|
+
], ObligationSingleSuccessResponse.prototype, "data", 2);
|
|
369
|
+
var OfferListResponse = class extends SuccessResponse {
|
|
370
|
+
};
|
|
371
|
+
__decorateClass([
|
|
372
|
+
ApiProperty({ type: "string", nullable: true, example: offerCursorExample })
|
|
373
|
+
], OfferListResponse.prototype, "cursor", 2);
|
|
374
|
+
__decorateClass([
|
|
375
|
+
ApiProperty({
|
|
376
|
+
type: () => [OfferListItemResponse],
|
|
377
|
+
description: "Offers matching the provided filters.",
|
|
378
|
+
example: [offerExample]
|
|
379
|
+
})
|
|
380
|
+
], OfferListResponse.prototype, "data", 2);
|
|
381
|
+
var RouterStatusDataResponse = class {
|
|
382
|
+
};
|
|
383
|
+
__decorateClass([
|
|
384
|
+
ApiProperty({ type: "string", enum: ["live", "syncing"], example: routerStatusExample.status })
|
|
385
|
+
], RouterStatusDataResponse.prototype, "status", 2);
|
|
386
|
+
var RouterStatusSuccessResponse = class extends SuccessResponse {
|
|
387
|
+
};
|
|
388
|
+
__decorateClass([
|
|
389
|
+
ApiProperty({
|
|
390
|
+
type: () => RouterStatusDataResponse,
|
|
391
|
+
description: "Aggregated router status.",
|
|
392
|
+
example: routerStatusExample
|
|
393
|
+
})
|
|
394
|
+
], RouterStatusSuccessResponse.prototype, "data", 2);
|
|
395
|
+
var CollectorHealthResponse = class {
|
|
396
|
+
};
|
|
397
|
+
__decorateClass([
|
|
398
|
+
ApiProperty({ type: "string", example: collectorsHealthExample.name })
|
|
399
|
+
], CollectorHealthResponse.prototype, "name", 2);
|
|
400
|
+
__decorateClass([
|
|
401
|
+
ApiProperty({ type: "string", example: collectorsHealthExample.chain_id })
|
|
402
|
+
], CollectorHealthResponse.prototype, "chain_id", 2);
|
|
403
|
+
__decorateClass([
|
|
404
|
+
ApiProperty({ type: "number", nullable: true, example: collectorsHealthExample.block_number })
|
|
405
|
+
], CollectorHealthResponse.prototype, "block_number", 2);
|
|
406
|
+
__decorateClass([
|
|
407
|
+
ApiProperty({ type: "string", nullable: true, example: collectorsHealthExample.updated_at })
|
|
408
|
+
], CollectorHealthResponse.prototype, "updated_at", 2);
|
|
409
|
+
__decorateClass([
|
|
410
|
+
ApiProperty({ type: "number", nullable: true, example: collectorsHealthExample.lag })
|
|
411
|
+
], CollectorHealthResponse.prototype, "lag", 2);
|
|
412
|
+
__decorateClass([
|
|
413
|
+
ApiProperty({
|
|
414
|
+
type: "string",
|
|
415
|
+
enum: ["live", "lagging", "unknown"],
|
|
416
|
+
example: collectorsHealthExample.status
|
|
417
|
+
})
|
|
418
|
+
], CollectorHealthResponse.prototype, "status", 2);
|
|
419
|
+
var CollectorsHealthSuccessResponse = class extends SuccessResponse {
|
|
420
|
+
};
|
|
421
|
+
__decorateClass([
|
|
422
|
+
ApiProperty({
|
|
423
|
+
type: () => [CollectorHealthResponse],
|
|
424
|
+
description: "Collectors health details and sync status.",
|
|
425
|
+
example: [collectorsHealthExample]
|
|
426
|
+
})
|
|
427
|
+
], CollectorsHealthSuccessResponse.prototype, "data", 2);
|
|
428
|
+
var ChainHealthResponse = class {
|
|
429
|
+
};
|
|
430
|
+
__decorateClass([
|
|
431
|
+
ApiProperty({ type: "string", example: chainsHealthExample.chain_id })
|
|
432
|
+
], ChainHealthResponse.prototype, "chain_id", 2);
|
|
433
|
+
__decorateClass([
|
|
434
|
+
ApiProperty({ type: "number", example: chainsHealthExample.block_number })
|
|
435
|
+
], ChainHealthResponse.prototype, "block_number", 2);
|
|
436
|
+
__decorateClass([
|
|
437
|
+
ApiProperty({ type: "string", example: chainsHealthExample.updated_at })
|
|
438
|
+
], ChainHealthResponse.prototype, "updated_at", 2);
|
|
439
|
+
var ChainsHealthSuccessResponse = class extends SuccessResponse {
|
|
440
|
+
};
|
|
441
|
+
__decorateClass([
|
|
442
|
+
ApiProperty({
|
|
443
|
+
type: () => [ChainHealthResponse],
|
|
444
|
+
description: "Latest processed block per chain.",
|
|
445
|
+
example: [chainsHealthExample]
|
|
446
|
+
})
|
|
447
|
+
], ChainsHealthSuccessResponse.prototype, "data", 2);
|
|
448
|
+
var OffersController = class {
|
|
449
|
+
async getOffers() {
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
__decorateClass([
|
|
453
|
+
ApiOperation({
|
|
454
|
+
methods: ["get"],
|
|
455
|
+
path: "/v1/offers",
|
|
456
|
+
summary: "List all offers",
|
|
457
|
+
description: "Returns a list of offers for a given obligation and side. Offers are sorted by the best rate (depending on the side), their block number (older offers first) and their assets (bigger offers first)."
|
|
458
|
+
}),
|
|
459
|
+
ApiQuery({ name: "side", type: "string", required: true, enum: ["buy", "sell"], example: "buy" }),
|
|
460
|
+
ApiQuery({
|
|
461
|
+
name: "obligation_id",
|
|
462
|
+
type: "string",
|
|
463
|
+
required: true,
|
|
464
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234",
|
|
465
|
+
description: "Obligation id used to filter offers."
|
|
466
|
+
}),
|
|
467
|
+
ApiQuery({
|
|
468
|
+
name: "cursor",
|
|
469
|
+
type: "string",
|
|
470
|
+
example: offerCursorExample,
|
|
471
|
+
description: "Pagination cursor in base64url-encoded format."
|
|
472
|
+
}),
|
|
473
|
+
ApiQuery({
|
|
474
|
+
name: "limit",
|
|
475
|
+
type: "number",
|
|
476
|
+
example: 10,
|
|
477
|
+
description: "Maximum number of offers to return."
|
|
478
|
+
}),
|
|
479
|
+
ApiResponse({ status: 200, description: "Success", type: OfferListResponse })
|
|
480
|
+
], OffersController.prototype, "getOffers", 1);
|
|
481
|
+
OffersController = __decorateClass([
|
|
482
|
+
ApiTags("Offers"),
|
|
483
|
+
ApiResponse({ status: 400, description: "Bad Request", type: BadRequestResponse })
|
|
484
|
+
], OffersController);
|
|
485
|
+
var HealthController = class {
|
|
486
|
+
async getRouterStatus() {
|
|
487
|
+
}
|
|
488
|
+
async getCollectorsHealth() {
|
|
489
|
+
}
|
|
490
|
+
async getChainsHealth() {
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
__decorateClass([
|
|
494
|
+
ApiOperation({
|
|
495
|
+
methods: ["get"],
|
|
496
|
+
path: "/v1/health",
|
|
497
|
+
summary: "Retrieve global health",
|
|
498
|
+
description: "Returns the aggregated status of the router."
|
|
499
|
+
}),
|
|
500
|
+
ApiResponse({ status: 200, description: "Success", type: RouterStatusSuccessResponse })
|
|
501
|
+
], HealthController.prototype, "getRouterStatus", 1);
|
|
502
|
+
__decorateClass([
|
|
503
|
+
ApiOperation({
|
|
504
|
+
methods: ["get"],
|
|
505
|
+
path: "/v1/health/collectors",
|
|
506
|
+
summary: "Retrieve collectors health",
|
|
507
|
+
description: "Returns the latest block numbers processed by collectors and their sync status."
|
|
508
|
+
}),
|
|
509
|
+
ApiResponse({ status: 200, description: "Success", type: CollectorsHealthSuccessResponse })
|
|
510
|
+
], HealthController.prototype, "getCollectorsHealth", 1);
|
|
511
|
+
__decorateClass([
|
|
512
|
+
ApiOperation({
|
|
513
|
+
methods: ["get"],
|
|
514
|
+
path: "/v1/health/chains",
|
|
515
|
+
summary: "Retrieve chains health",
|
|
516
|
+
description: "Returns the latest block that can be processed by collectors for each chain."
|
|
517
|
+
}),
|
|
518
|
+
ApiResponse({ status: 200, description: "Success", type: ChainsHealthSuccessResponse })
|
|
519
|
+
], HealthController.prototype, "getChainsHealth", 1);
|
|
520
|
+
HealthController = __decorateClass([
|
|
521
|
+
ApiTags("Health")
|
|
522
|
+
], HealthController);
|
|
523
|
+
var ObligationsController = class {
|
|
524
|
+
async getObligations() {
|
|
525
|
+
}
|
|
526
|
+
async getObligation() {
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
__decorateClass([
|
|
530
|
+
ApiOperation({
|
|
531
|
+
methods: ["get"],
|
|
532
|
+
path: "/v1/obligations",
|
|
533
|
+
summary: "List all obligations",
|
|
534
|
+
description: "Returns a list of obligations with their current best ask and bid. Obligations are sorted by their id in ascending order by default."
|
|
535
|
+
}),
|
|
536
|
+
ApiQuery({
|
|
537
|
+
name: "cursor",
|
|
538
|
+
type: "string",
|
|
539
|
+
example: obligationCursorExample
|
|
540
|
+
}),
|
|
541
|
+
ApiQuery({ name: "limit", type: "number", example: 10 }),
|
|
542
|
+
ApiResponse({ status: 200, description: "Success", type: ObligationListResponse })
|
|
543
|
+
], ObligationsController.prototype, "getObligations", 1);
|
|
544
|
+
__decorateClass([
|
|
545
|
+
ApiOperation({
|
|
546
|
+
methods: ["get"],
|
|
547
|
+
path: "/v1/obligations/{obligationId}",
|
|
548
|
+
summary: "Get an obligation",
|
|
549
|
+
description: "Returns an obligation by its id."
|
|
550
|
+
}),
|
|
551
|
+
ApiResponse({ status: 200, description: "Success", type: ObligationSingleSuccessResponse })
|
|
552
|
+
], ObligationsController.prototype, "getObligation", 1);
|
|
553
|
+
ObligationsController = __decorateClass([
|
|
554
|
+
ApiTags("Obligations"),
|
|
555
|
+
ApiResponse({ status: 400, description: "Bad Request", type: BadRequestResponse })
|
|
556
|
+
], ObligationsController);
|
|
557
|
+
var OpenApi = async () => await generateDocument({
|
|
558
|
+
controllers: [OffersController, ObligationsController, HealthController],
|
|
559
|
+
document: {
|
|
560
|
+
openapi: "3.1.0",
|
|
561
|
+
info: {
|
|
562
|
+
title: "Router API",
|
|
563
|
+
version: "1.0.0",
|
|
564
|
+
description: "API for the Morpho Router"
|
|
565
|
+
},
|
|
566
|
+
servers: [
|
|
567
|
+
{
|
|
568
|
+
url: "https://router.morpho.dev",
|
|
569
|
+
description: "Production server"
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
url: "http://localhost:7891",
|
|
573
|
+
description: "Local development server"
|
|
574
|
+
}
|
|
575
|
+
]
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// src/database/utils/Cursor.ts
|
|
580
|
+
var Cursor_exports = {};
|
|
581
|
+
__export(Cursor_exports, {
|
|
582
|
+
decode: () => decode,
|
|
583
|
+
encode: () => encode,
|
|
584
|
+
validate: () => validate
|
|
585
|
+
});
|
|
586
|
+
function validate(cursor) {
|
|
587
|
+
if (!cursor || typeof cursor !== "object") {
|
|
588
|
+
throw new Error("Cursor must be an object");
|
|
589
|
+
}
|
|
590
|
+
const c = cursor;
|
|
591
|
+
if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
if (!["asc", "desc"].includes(c.dir)) {
|
|
597
|
+
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
598
|
+
}
|
|
599
|
+
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
600
|
+
throw new Error(
|
|
601
|
+
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
const validations = {
|
|
605
|
+
rate: {
|
|
606
|
+
field: "rate",
|
|
607
|
+
type: "string",
|
|
608
|
+
pattern: /^\d+$/,
|
|
609
|
+
error: "numeric string"
|
|
610
|
+
},
|
|
611
|
+
amount: {
|
|
612
|
+
field: "assets",
|
|
613
|
+
type: "string",
|
|
614
|
+
pattern: /^\d+$/,
|
|
615
|
+
error: "numeric string"
|
|
616
|
+
},
|
|
617
|
+
maturity: {
|
|
618
|
+
field: "maturity",
|
|
619
|
+
type: "number",
|
|
620
|
+
validator: (val) => val > 0,
|
|
621
|
+
error: "positive number"
|
|
622
|
+
},
|
|
623
|
+
expiry: {
|
|
624
|
+
field: "expiry",
|
|
625
|
+
type: "number",
|
|
626
|
+
validator: (val) => val > 0,
|
|
627
|
+
error: "positive number"
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
const validation = validations[c.sort];
|
|
631
|
+
if (!validation) {
|
|
632
|
+
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
633
|
+
}
|
|
634
|
+
const fieldValue = c[validation.field];
|
|
635
|
+
if (!fieldValue) {
|
|
636
|
+
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
637
|
+
}
|
|
638
|
+
if (typeof fieldValue !== validation.type) {
|
|
639
|
+
throw new Error(
|
|
640
|
+
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
644
|
+
throw new Error(
|
|
645
|
+
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
if (validation.validator && !validation.validator(fieldValue)) {
|
|
649
|
+
throw new Error(
|
|
650
|
+
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
if (c.page !== void 0) {
|
|
654
|
+
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
655
|
+
throw new Error("Invalid page: must be a positive integer");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
function encode(c) {
|
|
661
|
+
return Base64.encodeURL(JSON.stringify(c));
|
|
662
|
+
}
|
|
663
|
+
function decode(token2) {
|
|
664
|
+
if (!token2) return null;
|
|
665
|
+
const decoded = JSON.parse(Base64.decode(token2));
|
|
666
|
+
validate(decoded);
|
|
667
|
+
return decoded;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/api/Schema/requests.ts
|
|
671
|
+
var MAX_LIMIT = 100;
|
|
672
|
+
var DEFAULT_LIMIT = 20;
|
|
673
|
+
var PaginationQueryParams = z9.object({
|
|
674
|
+
cursor: z9.string().optional().refine(
|
|
675
|
+
(val) => {
|
|
676
|
+
if (!val) return true;
|
|
677
|
+
try {
|
|
678
|
+
const decoded = Cursor_exports.decode(val);
|
|
679
|
+
return decoded !== null;
|
|
680
|
+
} catch (_error) {
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
686
|
+
}
|
|
687
|
+
).meta({
|
|
688
|
+
description: "Pagination cursor in base64url-encoded format",
|
|
689
|
+
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
690
|
+
}),
|
|
691
|
+
limit: z9.string().regex(/^[1-9]\d*$/, {
|
|
692
|
+
message: "Limit must be a positive integer"
|
|
693
|
+
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
694
|
+
z9.number().max(MAX_LIMIT, {
|
|
695
|
+
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
696
|
+
})
|
|
697
|
+
).optional().default(DEFAULT_LIMIT).meta({
|
|
698
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
699
|
+
example: 10
|
|
700
|
+
})
|
|
701
|
+
});
|
|
702
|
+
var GetOffersQueryParams = z9.object({
|
|
703
|
+
...PaginationQueryParams.shape,
|
|
704
|
+
side: z9.enum(["buy", "sell"]).meta({
|
|
705
|
+
description: "Side of the offer.",
|
|
706
|
+
example: "buy"
|
|
707
|
+
}),
|
|
708
|
+
obligation_id: z9.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
709
|
+
description: "Offers obligation id",
|
|
710
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
711
|
+
})
|
|
712
|
+
});
|
|
713
|
+
var GetObligationsQueryParams = z9.object({
|
|
714
|
+
...PaginationQueryParams.shape,
|
|
715
|
+
cursor: z9.string().optional().meta({
|
|
716
|
+
description: "Obligation id cursor",
|
|
717
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
718
|
+
})
|
|
719
|
+
});
|
|
720
|
+
var GetObligationParams = z9.object({
|
|
721
|
+
obligation_id: z9.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
722
|
+
description: "Obligation id",
|
|
723
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
724
|
+
})
|
|
725
|
+
});
|
|
726
|
+
var schemas = {
|
|
727
|
+
get_offers: GetOffersQueryParams,
|
|
728
|
+
get_obligations: GetObligationsQueryParams,
|
|
729
|
+
get_obligation: GetObligationParams
|
|
730
|
+
};
|
|
731
|
+
function parse(action, query) {
|
|
732
|
+
return schemas[action].parse(query);
|
|
733
|
+
}
|
|
734
|
+
function safeParse(action, query, error) {
|
|
735
|
+
return schemas[action].safeParse(query, {
|
|
736
|
+
error
|
|
737
|
+
});
|
|
121
738
|
}
|
|
122
739
|
|
|
740
|
+
// src/client/Client.ts
|
|
741
|
+
var Client_exports = {};
|
|
742
|
+
__export(Client_exports, {
|
|
743
|
+
HttpForbiddenError: () => HttpForbiddenError,
|
|
744
|
+
HttpGetApiFailedError: () => HttpGetApiFailedError,
|
|
745
|
+
HttpRateLimitError: () => HttpRateLimitError,
|
|
746
|
+
HttpUnauthorizedError: () => HttpUnauthorizedError,
|
|
747
|
+
InvalidUrlError: () => InvalidUrlError,
|
|
748
|
+
connect: () => connect,
|
|
749
|
+
getObligations: () => getObligations,
|
|
750
|
+
getOffers: () => getOffers
|
|
751
|
+
});
|
|
752
|
+
|
|
123
753
|
// src/core/Abi.ts
|
|
124
754
|
var Abi_exports = {};
|
|
125
755
|
__export(Abi_exports, {
|
|
@@ -317,11 +947,13 @@ var Morpho = [
|
|
|
317
947
|
var Callback_exports = {};
|
|
318
948
|
__export(Callback_exports, {
|
|
319
949
|
CallbackType: () => CallbackType,
|
|
320
|
-
|
|
950
|
+
decode: () => decode2,
|
|
321
951
|
decodeBuyVaultV1Callback: () => decodeBuyVaultV1Callback,
|
|
322
952
|
decodeSellERC20Callback: () => decodeSellERC20Callback,
|
|
953
|
+
encode: () => encode2,
|
|
323
954
|
encodeBuyVaultV1Callback: () => encodeBuyVaultV1Callback,
|
|
324
|
-
encodeSellERC20Callback: () => encodeSellERC20Callback
|
|
955
|
+
encodeSellERC20Callback: () => encodeSellERC20Callback,
|
|
956
|
+
isEmptyCallback: () => isEmptyCallback
|
|
325
957
|
});
|
|
326
958
|
var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
327
959
|
CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
|
|
@@ -329,19 +961,27 @@ var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
|
|
|
329
961
|
CallbackType2["SellERC20Callback"] = "sell_erc20_callback";
|
|
330
962
|
return CallbackType2;
|
|
331
963
|
})(CallbackType || {});
|
|
332
|
-
var
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
"
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
964
|
+
var isEmptyCallback = (offer) => offer.callback.data === "0x";
|
|
965
|
+
function decode2(type, data) {
|
|
966
|
+
switch (type) {
|
|
967
|
+
case "buy_vault_v1_callback" /* BuyVaultV1Callback */:
|
|
968
|
+
return decodeBuyVaultV1Callback(data);
|
|
969
|
+
case "sell_erc20_callback" /* SellERC20Callback */:
|
|
970
|
+
return decodeSellERC20Callback(data);
|
|
971
|
+
default:
|
|
972
|
+
throw new Error("Invalid callback type");
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function encode2(type, data) {
|
|
976
|
+
switch (type) {
|
|
977
|
+
case "buy_vault_v1_callback" /* BuyVaultV1Callback */:
|
|
978
|
+
return encodeBuyVaultV1Callback(data);
|
|
979
|
+
case "sell_erc20_callback" /* SellERC20Callback */:
|
|
980
|
+
return encodeSellERC20Callback(data);
|
|
981
|
+
default:
|
|
982
|
+
throw new Error("Invalid callback type");
|
|
983
|
+
}
|
|
984
|
+
}
|
|
345
985
|
function decodeBuyVaultV1Callback(data) {
|
|
346
986
|
if (!data || data === "0x") throw new Error("Empty callback data");
|
|
347
987
|
try {
|
|
@@ -483,74 +1123,30 @@ var chains = {
|
|
|
483
1123
|
...mainnet,
|
|
484
1124
|
id: ChainId.ETHEREUM,
|
|
485
1125
|
name: "ethereum",
|
|
486
|
-
whitelistedAssets: new Set(
|
|
487
|
-
[
|
|
488
|
-
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
489
|
-
// USDC
|
|
490
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
491
|
-
// DAI
|
|
492
|
-
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
493
|
-
// WETH
|
|
494
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
495
|
-
// WBTC
|
|
496
|
-
].map((address) => address.toLowerCase())
|
|
497
|
-
),
|
|
498
1126
|
morpho: "0x0000000000000000000000000000000000000000",
|
|
499
1127
|
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
500
1128
|
mempool: {
|
|
501
1129
|
address: "0x0000000000000000000000000000000000000000",
|
|
502
1130
|
deploymentBlock: 23347674,
|
|
503
1131
|
reindexBuffer: 10
|
|
504
|
-
},
|
|
505
|
-
vaultV1Factory: {
|
|
506
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
507
|
-
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
508
1132
|
}
|
|
509
1133
|
},
|
|
510
1134
|
base: {
|
|
511
1135
|
...base,
|
|
512
1136
|
id: ChainId.BASE,
|
|
513
1137
|
name: "base",
|
|
514
|
-
whitelistedAssets: new Set(
|
|
515
|
-
[
|
|
516
|
-
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
517
|
-
// USDC
|
|
518
|
-
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
|
|
519
|
-
// DAI
|
|
520
|
-
"0x4200000000000000000000000000000000000006",
|
|
521
|
-
// WETH
|
|
522
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
523
|
-
// WBTC
|
|
524
|
-
].map((address) => address.toLowerCase())
|
|
525
|
-
),
|
|
526
1138
|
morpho: "0x0000000000000000000000000000000000000000",
|
|
527
1139
|
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
528
1140
|
mempool: {
|
|
529
1141
|
address: "0x0000000000000000000000000000000000000000",
|
|
530
1142
|
deploymentBlock: 35449942,
|
|
531
1143
|
reindexBuffer: 10
|
|
532
|
-
},
|
|
533
|
-
vaultV1Factory: {
|
|
534
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
535
|
-
"v1.1": "0xFf62A7c278C62eD665133147129245053Bbf5918"
|
|
536
1144
|
}
|
|
537
1145
|
},
|
|
538
1146
|
"ethereum-virtual-testnet": {
|
|
539
1147
|
...mainnet,
|
|
540
1148
|
id: ChainId["ETHEREUM-VIRTUAL-TESTNET"],
|
|
541
1149
|
name: "ethereum-virtual-testnet",
|
|
542
|
-
whitelistedAssets: new Set(
|
|
543
|
-
[
|
|
544
|
-
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
545
|
-
// USDC
|
|
546
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
547
|
-
// DAI
|
|
548
|
-
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
549
|
-
// WETH
|
|
550
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
551
|
-
// WBTC
|
|
552
|
-
].map((address) => address.toLowerCase())
|
|
553
|
-
),
|
|
554
1150
|
morpho: "0x11a002d45db720ed47a80d2f3489cba5b833eaf5",
|
|
555
1151
|
// @TODO: This is mock Consumed contract, update with Terms once stable
|
|
556
1152
|
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -558,28 +1154,12 @@ var chains = {
|
|
|
558
1154
|
address: "0x5b06224f736a57635b5bcb50b8ef178b189107cb",
|
|
559
1155
|
deploymentBlock: 23224302,
|
|
560
1156
|
reindexBuffer: 10
|
|
561
|
-
},
|
|
562
|
-
vaultV1Factory: {
|
|
563
|
-
"v1.0": "0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
564
|
-
"v1.1": "0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
565
1157
|
}
|
|
566
1158
|
},
|
|
567
1159
|
anvil: {
|
|
568
1160
|
...anvil,
|
|
569
1161
|
id: ChainId.ANVIL,
|
|
570
1162
|
name: "anvil",
|
|
571
|
-
whitelistedAssets: new Set(
|
|
572
|
-
[
|
|
573
|
-
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
574
|
-
// USDC
|
|
575
|
-
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
576
|
-
// DAI
|
|
577
|
-
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
578
|
-
// WETH
|
|
579
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
580
|
-
// WBTC
|
|
581
|
-
].map((address) => address.toLowerCase())
|
|
582
|
-
),
|
|
583
1163
|
morpho: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
584
1164
|
morphoBlue: "0x0000000000000000000000000000000000000000",
|
|
585
1165
|
// Set dynamically in tests
|
|
@@ -587,10 +1167,6 @@ var chains = {
|
|
|
587
1167
|
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
588
1168
|
deploymentBlock: 23223727,
|
|
589
1169
|
reindexBuffer: 10
|
|
590
|
-
},
|
|
591
|
-
vaultV1Factory: {
|
|
592
|
-
"v1.0": "0x0000000000000000000000000000000000000000",
|
|
593
|
-
"v1.1": "0x0000000000000000000000000000000000000000"
|
|
594
1170
|
}
|
|
595
1171
|
}
|
|
596
1172
|
};
|
|
@@ -605,24 +1181,24 @@ async function* streamLogs(parameters) {
|
|
|
605
1181
|
event,
|
|
606
1182
|
blockNumberGte,
|
|
607
1183
|
blockNumberLte,
|
|
608
|
-
order = "desc",
|
|
1184
|
+
order: order2 = "desc",
|
|
609
1185
|
options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = DEFAULT_BLOCK_WINDOW } = {}
|
|
610
1186
|
} = parameters;
|
|
611
1187
|
if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);
|
|
612
1188
|
if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);
|
|
613
|
-
if (
|
|
1189
|
+
if (order2 === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
|
|
614
1190
|
const latestBlock = (await getBlock(client, { blockTag: "latest", includeTransactions: false })).number;
|
|
615
1191
|
let toBlock = 0n;
|
|
616
|
-
if (
|
|
1192
|
+
if (order2 === "asc")
|
|
617
1193
|
toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), latestBlock);
|
|
618
|
-
if (
|
|
1194
|
+
if (order2 === "desc")
|
|
619
1195
|
toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
|
|
620
1196
|
let fromBlock = 0n;
|
|
621
|
-
if (
|
|
622
|
-
if (
|
|
1197
|
+
if (order2 === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
|
|
1198
|
+
if (order2 === "desc")
|
|
623
1199
|
fromBlock = max(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
|
|
624
|
-
if (
|
|
625
|
-
if (
|
|
1200
|
+
if (order2 === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
|
|
1201
|
+
if (order2 === "desc") fromBlock = max(fromBlock, toBlock - BigInt(blockWindow));
|
|
626
1202
|
if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);
|
|
627
1203
|
let streaming = true;
|
|
628
1204
|
while (streaming) {
|
|
@@ -634,10 +1210,10 @@ async function* streamLogs(parameters) {
|
|
|
634
1210
|
});
|
|
635
1211
|
logs.sort((a, b) => {
|
|
636
1212
|
if (a.blockNumber !== b.blockNumber)
|
|
637
|
-
return
|
|
1213
|
+
return order2 === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
|
|
638
1214
|
if (a.transactionIndex !== b.transactionIndex)
|
|
639
|
-
return
|
|
640
|
-
return
|
|
1215
|
+
return order2 === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
|
|
1216
|
+
return order2 === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
|
|
641
1217
|
});
|
|
642
1218
|
for (const logBatch of batch(logs, maxBatchSize)) {
|
|
643
1219
|
if (logBatch.length === 0) break;
|
|
@@ -648,16 +1224,16 @@ async function* streamLogs(parameters) {
|
|
|
648
1224
|
Number(logBatch[logBatch.length - 1]?.blockNumber)
|
|
649
1225
|
) : (
|
|
650
1226
|
// if the batch is not full, return `toBlock` or `fromBlock` to indicate until which block the logs were fetched
|
|
651
|
-
|
|
1227
|
+
order2 === "asc" ? Number(toBlock) : Number(fromBlock)
|
|
652
1228
|
)
|
|
653
1229
|
};
|
|
654
1230
|
}
|
|
655
|
-
streaming =
|
|
656
|
-
if (
|
|
1231
|
+
streaming = order2 === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
|
|
1232
|
+
if (order2 === "asc") {
|
|
657
1233
|
fromBlock = min(BigInt(toBlock) + 1n, latestBlock);
|
|
658
1234
|
toBlock = min(fromBlock + BigInt(blockWindow), latestBlock);
|
|
659
1235
|
}
|
|
660
|
-
if (
|
|
1236
|
+
if (order2 === "desc") {
|
|
661
1237
|
const lowerBound = BigInt(blockNumberGte || 0);
|
|
662
1238
|
const windowSize = BigInt(blockWindow);
|
|
663
1239
|
const nextToBlock = max(fromBlock - 1n, lowerBound);
|
|
@@ -666,7 +1242,7 @@ async function* streamLogs(parameters) {
|
|
|
666
1242
|
fromBlock = nextFromBlock;
|
|
667
1243
|
}
|
|
668
1244
|
}
|
|
669
|
-
yield { logs: [], blockNumber:
|
|
1245
|
+
yield { logs: [], blockNumber: order2 === "asc" ? Number(toBlock) : Number(fromBlock) };
|
|
670
1246
|
return;
|
|
671
1247
|
}
|
|
672
1248
|
var InvalidBlockRangeError = class extends BaseError {
|
|
@@ -705,7 +1281,8 @@ var Collateral_exports = {};
|
|
|
705
1281
|
__export(Collateral_exports, {
|
|
706
1282
|
CollateralSchema: () => CollateralSchema,
|
|
707
1283
|
CollateralsSchema: () => CollateralsSchema,
|
|
708
|
-
from: () => from4
|
|
1284
|
+
from: () => from4,
|
|
1285
|
+
random: () => random
|
|
709
1286
|
});
|
|
710
1287
|
var transformHex = (val, ctx) => {
|
|
711
1288
|
if (isHex(val)) return val;
|
|
@@ -715,7 +1292,7 @@ var transformHex = (val, ctx) => {
|
|
|
715
1292
|
format: "hex",
|
|
716
1293
|
error: "not a hex"
|
|
717
1294
|
});
|
|
718
|
-
return
|
|
1295
|
+
return z9.NEVER;
|
|
719
1296
|
};
|
|
720
1297
|
var transformAddress = (val, ctx) => {
|
|
721
1298
|
if (isAddress(val.toLowerCase())) return val.toLowerCase();
|
|
@@ -725,7 +1302,7 @@ var transformAddress = (val, ctx) => {
|
|
|
725
1302
|
format: "address",
|
|
726
1303
|
error: "not a valid address"
|
|
727
1304
|
});
|
|
728
|
-
return
|
|
1305
|
+
return z9.NEVER;
|
|
729
1306
|
};
|
|
730
1307
|
|
|
731
1308
|
// src/core/LLTV.ts
|
|
@@ -765,7 +1342,7 @@ var InvalidLLTVError = class extends BaseError {
|
|
|
765
1342
|
__publicField(this, "name", "LLTV.InvalidLLTVError");
|
|
766
1343
|
}
|
|
767
1344
|
};
|
|
768
|
-
var LLTVSchema =
|
|
1345
|
+
var LLTVSchema = z9.bigint({ coerce: true }).refine(
|
|
769
1346
|
(lltv) => {
|
|
770
1347
|
try {
|
|
771
1348
|
from3(lltv);
|
|
@@ -782,12 +1359,12 @@ var LLTVSchema = z7.bigint({ coerce: true }).refine(
|
|
|
782
1359
|
).transform((lltv) => from3(lltv));
|
|
783
1360
|
|
|
784
1361
|
// src/core/Collateral.ts
|
|
785
|
-
var CollateralSchema =
|
|
786
|
-
asset:
|
|
787
|
-
oracle:
|
|
1362
|
+
var CollateralSchema = z9.object({
|
|
1363
|
+
asset: z9.string().transform(transformAddress),
|
|
1364
|
+
oracle: z9.string().transform(transformAddress),
|
|
788
1365
|
lltv: LLTVSchema
|
|
789
1366
|
});
|
|
790
|
-
var CollateralsSchema =
|
|
1367
|
+
var CollateralsSchema = z9.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine(
|
|
791
1368
|
(collaterals) => {
|
|
792
1369
|
for (let i = 1; i < collaterals.length; i++) {
|
|
793
1370
|
if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) {
|
|
@@ -822,6 +1399,13 @@ var from4 = (parameters) => {
|
|
|
822
1399
|
oracle: parameters.oracle.toLowerCase()
|
|
823
1400
|
};
|
|
824
1401
|
};
|
|
1402
|
+
function random() {
|
|
1403
|
+
return from4({
|
|
1404
|
+
asset: privateKeyToAccount(generatePrivateKey()).address,
|
|
1405
|
+
oracle: privateKeyToAccount(generatePrivateKey()).address,
|
|
1406
|
+
lltv: 0.965
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
825
1409
|
|
|
826
1410
|
// src/core/Liquidity.ts
|
|
827
1411
|
var Liquidity_exports = {};
|
|
@@ -845,20 +1429,20 @@ function calculateMaxDebt(amount, oraclePrice, lltv) {
|
|
|
845
1429
|
return maxDebt;
|
|
846
1430
|
}
|
|
847
1431
|
function generateBalancePoolId(parameters) {
|
|
848
|
-
const { user, chainId, token } = parameters;
|
|
849
|
-
return `${user}-${chainId.toString()}-${
|
|
1432
|
+
const { user, chainId, token: token2 } = parameters;
|
|
1433
|
+
return `${user}-${chainId.toString()}-${token2}-balance`.toLowerCase();
|
|
850
1434
|
}
|
|
851
1435
|
function generateAllowancePoolId(parameters) {
|
|
852
|
-
const { user, chainId, token } = parameters;
|
|
853
|
-
return `${user}-${chainId.toString()}-${
|
|
1436
|
+
const { user, chainId, token: token2 } = parameters;
|
|
1437
|
+
return `${user}-${chainId.toString()}-${token2}-allowance`.toLowerCase();
|
|
854
1438
|
}
|
|
855
1439
|
function generateSellERC20CallbackPoolId(parameters) {
|
|
856
|
-
const { user, chainId, obligationId: obligationId2, token, offerHash } = parameters;
|
|
857
|
-
return `${user}-${chainId.toString()}-${obligationId2}-${
|
|
1440
|
+
const { user, chainId, obligationId: obligationId2, token: token2, offerHash } = parameters;
|
|
1441
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token2}-${offerHash}-sell_erc20_callback`.toLowerCase();
|
|
858
1442
|
}
|
|
859
1443
|
function generateObligationCollateralPoolId(parameters) {
|
|
860
|
-
const { user, chainId, obligationId: obligationId2, token } = parameters;
|
|
861
|
-
return `${user}-${chainId.toString()}-${obligationId2}-${
|
|
1444
|
+
const { user, chainId, obligationId: obligationId2, token: token2 } = parameters;
|
|
1445
|
+
return `${user}-${chainId.toString()}-${obligationId2}-${token2}-obligation-collateral`.toLowerCase();
|
|
862
1446
|
}
|
|
863
1447
|
function generateBuyVaultCallbackPoolId(parameters) {
|
|
864
1448
|
const { user, chainId, vault, offerHash } = parameters;
|
|
@@ -888,12 +1472,13 @@ __export(Maturity_exports, {
|
|
|
888
1472
|
InvalidFormatError: () => InvalidFormatError,
|
|
889
1473
|
InvalidOptionError: () => InvalidOptionError2,
|
|
890
1474
|
MaturitySchema: () => MaturitySchema,
|
|
1475
|
+
MaturityType: () => MaturityType,
|
|
891
1476
|
from: () => from5
|
|
892
1477
|
});
|
|
893
|
-
var MaturitySchema =
|
|
894
|
-
(
|
|
1478
|
+
var MaturitySchema = z9.number().int().refine(
|
|
1479
|
+
(maturity2) => {
|
|
895
1480
|
try {
|
|
896
|
-
from5(
|
|
1481
|
+
from5(maturity2);
|
|
897
1482
|
return true;
|
|
898
1483
|
} catch (_e) {
|
|
899
1484
|
return false;
|
|
@@ -909,7 +1494,16 @@ var MaturitySchema = z7.number().int().refine(
|
|
|
909
1494
|
}
|
|
910
1495
|
}
|
|
911
1496
|
}
|
|
912
|
-
).transform((
|
|
1497
|
+
).transform((maturity2) => maturity2);
|
|
1498
|
+
var MaturityType = /* @__PURE__ */ ((MaturityType2) => {
|
|
1499
|
+
MaturityType2["EndOfWeek"] = "end_of_week";
|
|
1500
|
+
MaturityType2["EndOfNextWeek"] = "end_of_next_week";
|
|
1501
|
+
MaturityType2["EndOfMonth"] = "end_of_month";
|
|
1502
|
+
MaturityType2["EndOfNextMonth"] = "end_of_next_month";
|
|
1503
|
+
MaturityType2["EndOfQuarter"] = "end_of_quarter";
|
|
1504
|
+
MaturityType2["EndOfNextQuarter"] = "end_of_next_quarter";
|
|
1505
|
+
return MaturityType2;
|
|
1506
|
+
})(MaturityType || {});
|
|
913
1507
|
var MaturityOptions = {
|
|
914
1508
|
end_of_week: () => endOfWeek(),
|
|
915
1509
|
end_of_next_week: () => endOfNextWeek(),
|
|
@@ -930,8 +1524,26 @@ function from5(ts) {
|
|
|
930
1524
|
}
|
|
931
1525
|
var endOfWeek = () => fridayOfWeek(0);
|
|
932
1526
|
var endOfNextWeek = () => fridayOfWeek(1);
|
|
933
|
-
var endOfMonth = () =>
|
|
934
|
-
|
|
1527
|
+
var endOfMonth = () => {
|
|
1528
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
1529
|
+
const year = now2.getUTCFullYear();
|
|
1530
|
+
const month = now2.getUTCMonth();
|
|
1531
|
+
const endOfMonth2 = lastFridayOfMonth(year, month);
|
|
1532
|
+
if (now2.getTime() > endOfMonth2 * 1e3) {
|
|
1533
|
+
return lastFridayOfMonth(year, month + 1);
|
|
1534
|
+
}
|
|
1535
|
+
return endOfMonth2;
|
|
1536
|
+
};
|
|
1537
|
+
var endOfNextMonth = () => {
|
|
1538
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
1539
|
+
const year = now2.getUTCFullYear();
|
|
1540
|
+
const month = now2.getUTCMonth();
|
|
1541
|
+
const endOfMonth2 = lastFridayOfMonth(year, month);
|
|
1542
|
+
if (now2.getTime() > endOfMonth2 * 1e3) {
|
|
1543
|
+
return lastFridayOfMonth(year, month + 2);
|
|
1544
|
+
}
|
|
1545
|
+
return lastFridayOfMonth(year, month + 1);
|
|
1546
|
+
};
|
|
935
1547
|
var endOfQuarter = () => lastFridayOfQuarter(0);
|
|
936
1548
|
var endOfNextQuarter = () => lastFridayOfQuarter(1);
|
|
937
1549
|
var fridayOfWeek = (weeksAhead = 0) => {
|
|
@@ -952,8 +1564,8 @@ var lastFridayOfMonth = (year, month) => {
|
|
|
952
1564
|
while (lastDayOfMonth15H.getUTCDay() !== 5) {
|
|
953
1565
|
lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate() - 1);
|
|
954
1566
|
}
|
|
955
|
-
const
|
|
956
|
-
return
|
|
1567
|
+
const maturity2 = lastDayOfMonth15H.setUTCDate(lastDayOfMonth15H.getUTCDate()) / 1e3;
|
|
1568
|
+
return maturity2;
|
|
957
1569
|
};
|
|
958
1570
|
var lastFridayOfQuarter = (quartersAhead = 0) => {
|
|
959
1571
|
const now2 = /* @__PURE__ */ new Date();
|
|
@@ -999,11 +1611,11 @@ __export(Obligation_exports, {
|
|
|
999
1611
|
from: () => from6,
|
|
1000
1612
|
fromSnakeCase: () => fromSnakeCase2,
|
|
1001
1613
|
id: () => id,
|
|
1002
|
-
random: () =>
|
|
1614
|
+
random: () => random2
|
|
1003
1615
|
});
|
|
1004
|
-
var ObligationSchema =
|
|
1005
|
-
chainId:
|
|
1006
|
-
loanToken:
|
|
1616
|
+
var ObligationSchema = z9.object({
|
|
1617
|
+
chainId: z9.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1618
|
+
loanToken: z9.string().transform(transformAddress),
|
|
1007
1619
|
collaterals: CollateralsSchema,
|
|
1008
1620
|
maturity: MaturitySchema
|
|
1009
1621
|
});
|
|
@@ -1061,7 +1673,7 @@ function id(obligation) {
|
|
|
1061
1673
|
)
|
|
1062
1674
|
);
|
|
1063
1675
|
}
|
|
1064
|
-
function
|
|
1676
|
+
function random2() {
|
|
1065
1677
|
return from6({
|
|
1066
1678
|
chainId: 1n,
|
|
1067
1679
|
loanToken: privateKeyToAccount(generatePrivateKey()).address,
|
|
@@ -1095,170 +1707,138 @@ __export(Offer_exports, {
|
|
|
1095
1707
|
InvalidOfferError: () => InvalidOfferError,
|
|
1096
1708
|
OfferHashSchema: () => OfferHashSchema,
|
|
1097
1709
|
OfferSchema: () => OfferSchema,
|
|
1710
|
+
StatusCode: () => StatusCode,
|
|
1098
1711
|
consumedEvent: () => consumedEvent,
|
|
1099
|
-
decode: () =>
|
|
1712
|
+
decode: () => decode4,
|
|
1100
1713
|
domain: () => domain,
|
|
1101
|
-
encode: () =>
|
|
1102
|
-
from: () =>
|
|
1714
|
+
encode: () => encode4,
|
|
1715
|
+
from: () => from8,
|
|
1103
1716
|
fromConsumedLog: () => fromConsumedLog,
|
|
1104
1717
|
fromSnakeCase: () => fromSnakeCase3,
|
|
1105
1718
|
hash: () => hash,
|
|
1106
1719
|
obligationId: () => obligationId,
|
|
1107
|
-
random: () =>
|
|
1720
|
+
random: () => random3,
|
|
1108
1721
|
sign: () => sign,
|
|
1722
|
+
signatureMsg: () => signatureMsg,
|
|
1109
1723
|
toSnakeCase: () => toSnakeCase2,
|
|
1110
1724
|
types: () => types
|
|
1111
1725
|
});
|
|
1112
1726
|
|
|
1113
|
-
// src/
|
|
1114
|
-
var
|
|
1115
|
-
__export(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
fromSnakeCase: () => fromSnakeCase,
|
|
1121
|
-
lazy: () => lazy,
|
|
1122
|
-
max: () => max,
|
|
1123
|
-
min: () => min,
|
|
1124
|
-
poll: () => poll,
|
|
1125
|
-
retry: () => retry,
|
|
1126
|
-
toSnakeCase: () => toSnakeCase,
|
|
1127
|
-
wait: () => wait
|
|
1727
|
+
// src/core/Tree.ts
|
|
1728
|
+
var Tree_exports = {};
|
|
1729
|
+
__export(Tree_exports, {
|
|
1730
|
+
VERSION: () => VERSION,
|
|
1731
|
+
decode: () => decode3,
|
|
1732
|
+
encode: () => encode3,
|
|
1733
|
+
from: () => from7
|
|
1128
1734
|
});
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
} catch (err) {
|
|
1137
|
-
lastErr = err;
|
|
1138
|
-
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
throw lastErr;
|
|
1735
|
+
var VERSION = 1;
|
|
1736
|
+
var from7 = (offers) => {
|
|
1737
|
+
const leaves = order(offers).map((offer) => {
|
|
1738
|
+
return [offer.hash];
|
|
1739
|
+
});
|
|
1740
|
+
const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
|
|
1741
|
+
return Object.assign(tree, { offers });
|
|
1142
1742
|
};
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1743
|
+
var byHashAsc = (a, b) => a.localeCompare(b);
|
|
1744
|
+
var order = (offers) => {
|
|
1745
|
+
return offers.sort((a, b) => byHashAsc(a.hash, b.hash));
|
|
1746
|
+
};
|
|
1747
|
+
var encode3 = (tree) => {
|
|
1748
|
+
assertRoot(tree.root, tree.offers);
|
|
1749
|
+
const offersPayload = tree.offers.map((offer) => ({
|
|
1750
|
+
offering: offer.offering,
|
|
1751
|
+
assets: offer.assets.toString(),
|
|
1752
|
+
rate: offer.rate.toString(),
|
|
1753
|
+
maturity: Number(offer.maturity),
|
|
1754
|
+
expiry: Number(offer.expiry),
|
|
1755
|
+
start: Number(offer.start),
|
|
1756
|
+
nonce: offer.nonce.toString(),
|
|
1757
|
+
buy: offer.buy,
|
|
1758
|
+
chainId: offer.chainId.toString(),
|
|
1759
|
+
loanToken: offer.loanToken,
|
|
1760
|
+
collaterals: offer.collaterals.map((c) => ({
|
|
1761
|
+
asset: c.asset,
|
|
1762
|
+
oracle: c.oracle,
|
|
1763
|
+
lltv: c.lltv.toString()
|
|
1764
|
+
})),
|
|
1765
|
+
callback: {
|
|
1766
|
+
address: offer.callback.address,
|
|
1767
|
+
data: offer.callback.data,
|
|
1768
|
+
gasLimit: offer.callback.gasLimit.toString()
|
|
1769
|
+
},
|
|
1770
|
+
signature: offer.signature,
|
|
1771
|
+
hash: offer.hash
|
|
1772
|
+
}));
|
|
1773
|
+
const compressed = gzip(JSON.stringify([tree.root, ...offersPayload]));
|
|
1774
|
+
const encoded = new Uint8Array(1 + compressed.length);
|
|
1775
|
+
encoded[0] = VERSION;
|
|
1776
|
+
encoded.set(compressed, 1);
|
|
1777
|
+
return bytesToHex(encoded);
|
|
1778
|
+
};
|
|
1779
|
+
var assertRoot = (root, offers) => {
|
|
1780
|
+
const tree = from7(offers);
|
|
1781
|
+
if (root !== tree.root) {
|
|
1782
|
+
throw new Error(`Invalid root: expected ${tree.root}, got ${root}`);
|
|
1159
1783
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
resolveNext?.();
|
|
1182
|
-
resolveNext = null;
|
|
1183
|
-
};
|
|
1184
|
-
unpoll = pollFn(emit, { stop });
|
|
1185
|
-
try {
|
|
1186
|
-
while (active) {
|
|
1187
|
-
if (queue.length === 0) await wait2();
|
|
1188
|
-
while (queue.length > 0 && active) yield queue.shift();
|
|
1189
|
-
}
|
|
1190
|
-
} finally {
|
|
1191
|
-
stop();
|
|
1192
|
-
}
|
|
1193
|
-
}();
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
// src/utils/wait.ts
|
|
1197
|
-
async function wait(time) {
|
|
1198
|
-
return new Promise((res) => setTimeout(res, time));
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
// src/utils/poll.ts
|
|
1202
|
-
function poll(fn, { interval }) {
|
|
1203
|
-
let active = true;
|
|
1204
|
-
const unwatch = () => active = false;
|
|
1205
|
-
const watch2 = async () => {
|
|
1206
|
-
await wait(interval);
|
|
1207
|
-
const poll2 = async () => {
|
|
1208
|
-
if (!active) return;
|
|
1209
|
-
await fn({ unpoll: unwatch });
|
|
1210
|
-
await wait(interval);
|
|
1211
|
-
poll2();
|
|
1212
|
-
};
|
|
1213
|
-
poll2();
|
|
1214
|
-
};
|
|
1215
|
-
watch2();
|
|
1216
|
-
return unwatch;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
// src/utils/time.ts
|
|
1220
|
-
var time_exports = {};
|
|
1221
|
-
__export(time_exports, {
|
|
1222
|
-
max: () => max2,
|
|
1223
|
-
now: () => now
|
|
1224
|
-
});
|
|
1225
|
-
function now() {
|
|
1226
|
-
return Math.floor(Date.now() / 1e3);
|
|
1227
|
-
}
|
|
1228
|
-
function max2() {
|
|
1229
|
-
return 864e16;
|
|
1230
|
-
}
|
|
1784
|
+
};
|
|
1785
|
+
var decode3 = (encoded) => {
|
|
1786
|
+
const bytes = hexToBytes(encoded);
|
|
1787
|
+
if (bytes.length < 2) {
|
|
1788
|
+
throw new Error("Invalid payload: too short");
|
|
1789
|
+
}
|
|
1790
|
+
const version = bytes[0];
|
|
1791
|
+
if (version !== (VERSION & 255)) {
|
|
1792
|
+
throw new Error(`Invalid version: expected ${VERSION}, got ${version}`);
|
|
1793
|
+
}
|
|
1794
|
+
const payload = bytes.slice(1);
|
|
1795
|
+
const decoded = ungzip(payload, { to: "string" });
|
|
1796
|
+
const data = JSON.parse(decoded);
|
|
1797
|
+
const root = data[0];
|
|
1798
|
+
const offers = data.slice(1).map((o) => OfferSchema({ omitConsumed: true, omitBlockNumber: true }).parse(o));
|
|
1799
|
+
const tree = from7(offers);
|
|
1800
|
+
if (root !== tree.root) {
|
|
1801
|
+
throw new Error(`Invalid root: expected ${tree.root}, got ${root}`);
|
|
1802
|
+
}
|
|
1803
|
+
return tree;
|
|
1804
|
+
};
|
|
1231
1805
|
|
|
1232
1806
|
// src/core/Offer.ts
|
|
1233
|
-
var
|
|
1807
|
+
var StatusCode = /* @__PURE__ */ ((StatusCode2) => {
|
|
1808
|
+
StatusCode2["VALID"] = "VALID";
|
|
1809
|
+
StatusCode2["NOT_ENOUGH_LIQUIDITY"] = "NOT_ENOUGH_LIQUIDITY";
|
|
1810
|
+
return StatusCode2;
|
|
1811
|
+
})(StatusCode || {});
|
|
1812
|
+
var OfferHashSchema = z9.string().regex(/^0x[0-9a-fA-F]{64}$/, {
|
|
1234
1813
|
message: "Hash must be a valid 32-byte hex string"
|
|
1235
1814
|
}).transform(transformHex);
|
|
1236
1815
|
var OfferSchema = (parameters) => {
|
|
1237
|
-
const { omitHash = false } = parameters || {};
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
rate: z7.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1816
|
+
const { omitHash = false, omitConsumed = false, omitBlockNumber = false } = parameters || {};
|
|
1817
|
+
let base = z9.object({
|
|
1818
|
+
offering: z9.string().transform(transformAddress),
|
|
1819
|
+
assets: z9.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1820
|
+
rate: z9.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1243
1821
|
maturity: MaturitySchema,
|
|
1244
|
-
expiry:
|
|
1245
|
-
start:
|
|
1246
|
-
nonce:
|
|
1247
|
-
buy:
|
|
1248
|
-
chainId:
|
|
1249
|
-
loanToken:
|
|
1822
|
+
expiry: z9.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1823
|
+
start: z9.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1824
|
+
nonce: z9.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1825
|
+
buy: z9.boolean(),
|
|
1826
|
+
chainId: z9.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
1827
|
+
loanToken: z9.string().transform(transformAddress),
|
|
1250
1828
|
collaterals: CollateralsSchema,
|
|
1251
|
-
callback:
|
|
1252
|
-
address:
|
|
1253
|
-
data:
|
|
1254
|
-
gasLimit:
|
|
1829
|
+
callback: z9.object({
|
|
1830
|
+
address: z9.string().transform(transformAddress),
|
|
1831
|
+
data: z9.string().transform(transformHex),
|
|
1832
|
+
gasLimit: z9.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1255
1833
|
}),
|
|
1256
|
-
|
|
1257
|
-
blockNumber: z7.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
1258
|
-
signature: z7.string().regex(/^0x[0-9a-fA-F]{130}$/, {
|
|
1834
|
+
signature: z9.string().regex(/^0x[0-9a-fA-F]{130}$/, {
|
|
1259
1835
|
message: "Signature must be a valid 65-byte hex string"
|
|
1260
1836
|
}).transform(transformHex).optional()
|
|
1261
1837
|
});
|
|
1838
|
+
if (!omitConsumed)
|
|
1839
|
+
base = base.extend({ consumed: z9.bigint({ coerce: true }).min(0n).max(maxUint256) });
|
|
1840
|
+
if (!omitBlockNumber)
|
|
1841
|
+
base = base.extend({ blockNumber: z9.number().int().max(Number.MAX_SAFE_INTEGER) });
|
|
1262
1842
|
if (!omitHash) base = base.extend({ hash: OfferHashSchema });
|
|
1263
1843
|
return base.refine((data) => data.start < data.expiry, {
|
|
1264
1844
|
message: "Start must be before expiry",
|
|
@@ -1268,7 +1848,7 @@ var OfferSchema = (parameters) => {
|
|
|
1268
1848
|
path: ["expiry"]
|
|
1269
1849
|
});
|
|
1270
1850
|
};
|
|
1271
|
-
function
|
|
1851
|
+
function from8(input) {
|
|
1272
1852
|
try {
|
|
1273
1853
|
const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
|
|
1274
1854
|
const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
|
|
@@ -1281,13 +1861,13 @@ function from7(input) {
|
|
|
1281
1861
|
}
|
|
1282
1862
|
}
|
|
1283
1863
|
function fromSnakeCase3(input) {
|
|
1284
|
-
return
|
|
1864
|
+
return from8(fromSnakeCase(input));
|
|
1285
1865
|
}
|
|
1286
1866
|
function toSnakeCase2(offer) {
|
|
1287
1867
|
return toSnakeCase(offer);
|
|
1288
1868
|
}
|
|
1289
|
-
function
|
|
1290
|
-
const
|
|
1869
|
+
function random3(config) {
|
|
1870
|
+
const chain2 = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains.ethereum;
|
|
1291
1871
|
const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : privateKeyToAccount(generatePrivateKey()).address;
|
|
1292
1872
|
const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [privateKeyToAccount(generatePrivateKey()).address];
|
|
1293
1873
|
const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
|
|
@@ -1295,7 +1875,7 @@ function random2(config) {
|
|
|
1295
1875
|
["end_of_month", 1],
|
|
1296
1876
|
["end_of_next_month", 1]
|
|
1297
1877
|
]);
|
|
1298
|
-
const
|
|
1878
|
+
const maturity2 = config?.maturity ?? from5(maturityOption);
|
|
1299
1879
|
const lltv = from3(
|
|
1300
1880
|
weightedChoice([
|
|
1301
1881
|
[0.385, 1],
|
|
@@ -1331,32 +1911,29 @@ function random2(config) {
|
|
|
1331
1911
|
const consumed = config?.consumed !== void 0 ? config.consumed : Math.random() < 0.8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
|
|
1332
1912
|
const callbackBySide = (() => {
|
|
1333
1913
|
if (buy) return { address: zeroAddress, data: "0x", gasLimit: 0n };
|
|
1334
|
-
const sellCallbackAddress =
|
|
1914
|
+
const sellCallbackAddress = "0x3333333333333333333333333333333333333333";
|
|
1335
1915
|
const amount = assetsScaled * 1000000000000000000000n;
|
|
1336
1916
|
const data = encodeSellERC20Callback({
|
|
1337
1917
|
collaterals: [collateralAsset],
|
|
1338
1918
|
amounts: [amount]
|
|
1339
1919
|
});
|
|
1340
|
-
return { address: sellCallbackAddress, data, gasLimit:
|
|
1920
|
+
return { address: sellCallbackAddress, data, gasLimit: 0n };
|
|
1341
1921
|
})();
|
|
1342
|
-
const offer =
|
|
1922
|
+
const offer = from8({
|
|
1343
1923
|
offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
|
|
1344
1924
|
assets: assetsScaled,
|
|
1345
1925
|
rate,
|
|
1346
|
-
maturity,
|
|
1347
|
-
expiry: config?.expiry ??
|
|
1348
|
-
start: config?.start ??
|
|
1926
|
+
maturity: maturity2,
|
|
1927
|
+
expiry: config?.expiry ?? maturity2 - 1,
|
|
1928
|
+
start: config?.start ?? maturity2 - 10,
|
|
1349
1929
|
nonce: BigInt(Math.floor(Math.random() * 1e6)),
|
|
1350
1930
|
buy,
|
|
1351
|
-
chainId:
|
|
1931
|
+
chainId: chain2.id,
|
|
1352
1932
|
loanToken,
|
|
1353
|
-
collaterals: config?.collaterals ??
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
lltv
|
|
1358
|
-
})
|
|
1359
|
-
],
|
|
1933
|
+
collaterals: config?.collaterals ?? Array.from({ length: Math.floor(Math.random() * 3) + 1 }, () => ({
|
|
1934
|
+
...random(),
|
|
1935
|
+
lltv
|
|
1936
|
+
})).sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
1360
1937
|
callback: config?.callback ?? callbackBySide,
|
|
1361
1938
|
consumed,
|
|
1362
1939
|
blockNumber: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
@@ -1404,31 +1981,16 @@ var types = {
|
|
|
1404
1981
|
{ name: "gasLimit", type: "uint256" }
|
|
1405
1982
|
]
|
|
1406
1983
|
};
|
|
1407
|
-
function sign(
|
|
1984
|
+
async function sign(offers, wallet) {
|
|
1408
1985
|
if (!wallet.account) throw new AccountNotSetError();
|
|
1409
|
-
return wallet.
|
|
1986
|
+
return wallet.signMessage({
|
|
1410
1987
|
account: wallet.account,
|
|
1411
|
-
|
|
1412
|
-
types,
|
|
1413
|
-
primaryType: "Offer",
|
|
1414
|
-
message: {
|
|
1415
|
-
offering: offer.offering.toLowerCase(),
|
|
1416
|
-
assets: offer.assets,
|
|
1417
|
-
rate: offer.rate,
|
|
1418
|
-
maturity: BigInt(offer.maturity),
|
|
1419
|
-
expiry: BigInt(offer.expiry),
|
|
1420
|
-
nonce: offer.nonce,
|
|
1421
|
-
buy: offer.buy,
|
|
1422
|
-
loanToken: offer.loanToken.toLowerCase(),
|
|
1423
|
-
collaterals: offer.collaterals,
|
|
1424
|
-
callback: {
|
|
1425
|
-
address: offer.callback.address.toLowerCase(),
|
|
1426
|
-
data: offer.callback.data,
|
|
1427
|
-
gasLimit: offer.callback.gasLimit
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1988
|
+
message: { raw: signatureMsg(offers) }
|
|
1430
1989
|
});
|
|
1431
1990
|
}
|
|
1991
|
+
function signatureMsg(offers) {
|
|
1992
|
+
return from7(offers).root;
|
|
1993
|
+
}
|
|
1432
1994
|
function hash(offer) {
|
|
1433
1995
|
return hashTypedData({
|
|
1434
1996
|
domain: domain(offer.chainId),
|
|
@@ -1493,7 +2055,7 @@ var OfferAbi = [
|
|
|
1493
2055
|
},
|
|
1494
2056
|
{ name: "signature", type: "bytes" }
|
|
1495
2057
|
];
|
|
1496
|
-
function
|
|
2058
|
+
function encode4(offer) {
|
|
1497
2059
|
return encodeAbiParameters(OfferAbi, [
|
|
1498
2060
|
offer.offering,
|
|
1499
2061
|
offer.assets,
|
|
@@ -1510,14 +2072,14 @@ function encode(offer) {
|
|
|
1510
2072
|
offer.signature ?? "0x"
|
|
1511
2073
|
]);
|
|
1512
2074
|
}
|
|
1513
|
-
function
|
|
2075
|
+
function decode4(data, blockNumber) {
|
|
1514
2076
|
let decoded;
|
|
1515
2077
|
try {
|
|
1516
2078
|
decoded = decodeAbiParameters(OfferAbi, data);
|
|
1517
2079
|
} catch (error) {
|
|
1518
2080
|
throw new InvalidOfferError(error);
|
|
1519
2081
|
}
|
|
1520
|
-
const offer =
|
|
2082
|
+
const offer = from8({
|
|
1521
2083
|
offering: decoded[0],
|
|
1522
2084
|
assets: decoded[1],
|
|
1523
2085
|
rate: decoded[2],
|
|
@@ -1585,20 +2147,20 @@ var Quote_exports = {};
|
|
|
1585
2147
|
__export(Quote_exports, {
|
|
1586
2148
|
InvalidQuoteError: () => InvalidQuoteError,
|
|
1587
2149
|
QuoteSchema: () => QuoteSchema,
|
|
1588
|
-
from: () =>
|
|
2150
|
+
from: () => from9,
|
|
1589
2151
|
fromSnakeCase: () => fromSnakeCase4,
|
|
1590
|
-
random: () =>
|
|
2152
|
+
random: () => random4
|
|
1591
2153
|
});
|
|
1592
|
-
var QuoteSchema =
|
|
1593
|
-
obligationId:
|
|
1594
|
-
ask:
|
|
1595
|
-
rate:
|
|
2154
|
+
var QuoteSchema = z9.object({
|
|
2155
|
+
obligationId: z9.string().transform(transformHex),
|
|
2156
|
+
ask: z9.object({
|
|
2157
|
+
rate: z9.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1596
2158
|
}),
|
|
1597
|
-
bid:
|
|
1598
|
-
rate:
|
|
2159
|
+
bid: z9.object({
|
|
2160
|
+
rate: z9.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1599
2161
|
})
|
|
1600
2162
|
});
|
|
1601
|
-
function
|
|
2163
|
+
function from9(parameters) {
|
|
1602
2164
|
try {
|
|
1603
2165
|
const parsedQuote = QuoteSchema.parse(parameters);
|
|
1604
2166
|
return {
|
|
@@ -1611,10 +2173,10 @@ function from8(parameters) {
|
|
|
1611
2173
|
}
|
|
1612
2174
|
}
|
|
1613
2175
|
function fromSnakeCase4(snake) {
|
|
1614
|
-
return
|
|
2176
|
+
return from9(fromSnakeCase(snake));
|
|
1615
2177
|
}
|
|
1616
|
-
function
|
|
1617
|
-
return
|
|
2178
|
+
function random4() {
|
|
2179
|
+
return from9({
|
|
1618
2180
|
obligationId: Obligation_exports.id(Obligation_exports.random()),
|
|
1619
2181
|
ask: {
|
|
1620
2182
|
rate: BigInt(Math.floor(Math.random() * 1e6))
|
|
@@ -1634,494 +2196,83 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
1634
2196
|
// src/core/types.ts
|
|
1635
2197
|
var BrandTypeId = Symbol.for("mempool/Brand");
|
|
1636
2198
|
|
|
1637
|
-
// src/
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
)
|
|
1653
|
-
}
|
|
1654
|
-
if (!["asc", "desc"].includes(c.dir)) {
|
|
1655
|
-
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
1656
|
-
}
|
|
1657
|
-
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
1658
|
-
throw new Error(
|
|
1659
|
-
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
1660
|
-
);
|
|
1661
|
-
}
|
|
1662
|
-
const validations = {
|
|
1663
|
-
rate: {
|
|
1664
|
-
field: "rate",
|
|
1665
|
-
type: "string",
|
|
1666
|
-
pattern: /^\d+$/,
|
|
1667
|
-
error: "numeric string"
|
|
1668
|
-
},
|
|
1669
|
-
amount: {
|
|
1670
|
-
field: "assets",
|
|
1671
|
-
type: "string",
|
|
1672
|
-
pattern: /^\d+$/,
|
|
1673
|
-
error: "numeric string"
|
|
1674
|
-
},
|
|
1675
|
-
maturity: {
|
|
1676
|
-
field: "maturity",
|
|
1677
|
-
type: "number",
|
|
1678
|
-
validator: (val) => val > 0,
|
|
1679
|
-
error: "positive number"
|
|
1680
|
-
},
|
|
1681
|
-
expiry: {
|
|
1682
|
-
field: "expiry",
|
|
1683
|
-
type: "number",
|
|
1684
|
-
validator: (val) => val > 0,
|
|
1685
|
-
error: "positive number"
|
|
1686
|
-
}
|
|
2199
|
+
// src/client/Client.ts
|
|
2200
|
+
function connect(parameters) {
|
|
2201
|
+
const u = new URL(parameters?.url || "https://router.morpho.dev");
|
|
2202
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") throw new InvalidUrlError(u.toString());
|
|
2203
|
+
const headers = parameters?.headers ?? new Headers();
|
|
2204
|
+
headers.set("Content-Type", "application/json");
|
|
2205
|
+
parameters?.apiKey !== void 0 ? headers.set("X-API-Key", parameters.apiKey) : null;
|
|
2206
|
+
const config = { url: u, headers };
|
|
2207
|
+
const apiClient = createOpenApiFetchClient({
|
|
2208
|
+
baseUrl: config.url.toString(),
|
|
2209
|
+
headers: config.headers
|
|
2210
|
+
});
|
|
2211
|
+
return {
|
|
2212
|
+
...config,
|
|
2213
|
+
getOffers: (parameters2) => getOffers(apiClient, parameters2),
|
|
2214
|
+
getObligations: (parameters2) => getObligations(apiClient, parameters2)
|
|
1687
2215
|
};
|
|
1688
|
-
const validation = validations[c.sort];
|
|
1689
|
-
if (!validation) {
|
|
1690
|
-
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
1691
|
-
}
|
|
1692
|
-
const fieldValue = c[validation.field];
|
|
1693
|
-
if (!fieldValue) {
|
|
1694
|
-
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
1695
|
-
}
|
|
1696
|
-
if (typeof fieldValue !== validation.type) {
|
|
1697
|
-
throw new Error(
|
|
1698
|
-
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
1702
|
-
throw new Error(
|
|
1703
|
-
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
1704
|
-
);
|
|
1705
|
-
}
|
|
1706
|
-
if (validation.validator && !validation.validator(fieldValue)) {
|
|
1707
|
-
throw new Error(
|
|
1708
|
-
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
1709
|
-
);
|
|
1710
|
-
}
|
|
1711
|
-
if (c.page !== void 0) {
|
|
1712
|
-
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
1713
|
-
throw new Error("Invalid page: must be a positive integer");
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
return true;
|
|
1717
2216
|
}
|
|
1718
|
-
function
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
// src/api/Schema/requests.ts
|
|
1729
|
-
var MAX_LIMIT = 100;
|
|
1730
|
-
var DEFAULT_LIMIT = 20;
|
|
1731
|
-
var PaginationQueryParams = z7.object({
|
|
1732
|
-
cursor: z7.string().optional().refine(
|
|
1733
|
-
(val) => {
|
|
1734
|
-
if (!val) return true;
|
|
1735
|
-
try {
|
|
1736
|
-
const decoded = Cursor_exports.decode(val);
|
|
1737
|
-
return decoded !== null;
|
|
1738
|
-
} catch (_error) {
|
|
1739
|
-
return false;
|
|
2217
|
+
async function getOffers(apiClient, parameters) {
|
|
2218
|
+
const { data, error, response } = await apiClient.GET("/v1/offers", {
|
|
2219
|
+
params: {
|
|
2220
|
+
query: {
|
|
2221
|
+
side: parameters.side,
|
|
2222
|
+
obligation_id: parameters.obligationId,
|
|
2223
|
+
cursor: parameters.cursor,
|
|
2224
|
+
limit: parameters.limit
|
|
1740
2225
|
}
|
|
1741
|
-
},
|
|
1742
|
-
{
|
|
1743
|
-
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1744
|
-
}
|
|
1745
|
-
).meta({
|
|
1746
|
-
description: "Pagination cursor in base64url-encoded format",
|
|
1747
|
-
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
1748
|
-
}),
|
|
1749
|
-
limit: z7.string().regex(/^[1-9]\d*$/, {
|
|
1750
|
-
message: "Limit must be a positive integer"
|
|
1751
|
-
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
1752
|
-
z7.number().max(MAX_LIMIT, {
|
|
1753
|
-
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
1754
|
-
})
|
|
1755
|
-
).optional().default(DEFAULT_LIMIT).meta({
|
|
1756
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
1757
|
-
example: 10
|
|
1758
|
-
})
|
|
1759
|
-
});
|
|
1760
|
-
var GetOffersQueryParams = z7.object({
|
|
1761
|
-
...PaginationQueryParams.shape,
|
|
1762
|
-
side: z7.enum(["buy", "sell"]).meta({
|
|
1763
|
-
description: "Side of the offer.",
|
|
1764
|
-
example: "buy"
|
|
1765
|
-
}),
|
|
1766
|
-
obligation_id: z7.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
1767
|
-
description: "Offers obligation id",
|
|
1768
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1769
|
-
})
|
|
1770
|
-
});
|
|
1771
|
-
var GetObligationsQueryParams = z7.object({
|
|
1772
|
-
...PaginationQueryParams.shape,
|
|
1773
|
-
cursor: z7.string().optional().meta({
|
|
1774
|
-
description: "Obligation id cursor",
|
|
1775
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1776
|
-
})
|
|
1777
|
-
});
|
|
1778
|
-
var schemas = {
|
|
1779
|
-
get_offers: GetOffersQueryParams,
|
|
1780
|
-
get_obligations: GetObligationsQueryParams
|
|
1781
|
-
};
|
|
1782
|
-
function parse(action, query) {
|
|
1783
|
-
return schemas[action].parse(query);
|
|
1784
|
-
}
|
|
1785
|
-
function safeParse(action, query, error) {
|
|
1786
|
-
return schemas[action].safeParse(query, {
|
|
1787
|
-
error
|
|
1788
|
-
});
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
// src/api/Schema/openapi.ts
|
|
1792
|
-
var timestampExample = "2024-01-01T12:00:00.000Z";
|
|
1793
|
-
var cursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
1794
|
-
function makeSuccessResponse(parameters) {
|
|
1795
|
-
const { dataSchema, dataDescription, dataExample, cursor } = parameters;
|
|
1796
|
-
const withDataMeta = dataDescription ? dataSchema.meta({ description: dataDescription }) : dataSchema;
|
|
1797
|
-
return z.object({
|
|
1798
|
-
status: z.literal("success"),
|
|
1799
|
-
cursor: z.string().nullable(),
|
|
1800
|
-
data: z.any(),
|
|
1801
|
-
meta: z.object({
|
|
1802
|
-
timestamp: z.string()
|
|
1803
|
-
})
|
|
1804
|
-
}).extend({
|
|
1805
|
-
data: withDataMeta
|
|
1806
|
-
}).meta({
|
|
1807
|
-
example: {
|
|
1808
|
-
status: "success",
|
|
1809
|
-
cursor,
|
|
1810
|
-
data: dataExample,
|
|
1811
|
-
meta: { timestamp: timestampExample }
|
|
1812
2226
|
}
|
|
1813
2227
|
});
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
dataSchema: z.array(z.any()),
|
|
1823
|
-
dataDescription: "Obligations known to the router.",
|
|
1824
|
-
dataExample: [toSnakeCase(Obligation_exports.random())],
|
|
1825
|
-
cursor: cursorExample
|
|
1826
|
-
});
|
|
1827
|
-
var RouterStatusSuccessResponseSchema = makeSuccessResponse({
|
|
1828
|
-
dataSchema: RouterStatusResponse,
|
|
1829
|
-
dataDescription: "Aggregated router status.",
|
|
1830
|
-
dataExample: { status: "live" },
|
|
1831
|
-
cursor: null
|
|
1832
|
-
});
|
|
1833
|
-
var CollectorsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1834
|
-
dataSchema: CollectorsHealthResponse,
|
|
1835
|
-
dataDescription: "Collectors health details and sync status.",
|
|
1836
|
-
dataExample: [
|
|
1837
|
-
{
|
|
1838
|
-
name: "mempool_offers",
|
|
1839
|
-
chain_id: "1",
|
|
1840
|
-
block_number: 21345678,
|
|
1841
|
-
updated_at: "2024-01-01T12:00:00.000Z",
|
|
1842
|
-
lag: 0,
|
|
1843
|
-
status: "live"
|
|
1844
|
-
}
|
|
1845
|
-
],
|
|
1846
|
-
cursor: null
|
|
1847
|
-
});
|
|
1848
|
-
var ChainsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1849
|
-
dataSchema: ChainsHealthResponse,
|
|
1850
|
-
dataDescription: "Latest processed block per chain.",
|
|
1851
|
-
dataExample: [
|
|
1852
|
-
{
|
|
1853
|
-
chain_id: "1",
|
|
1854
|
-
block_number: 21345678,
|
|
1855
|
-
updated_at: "2024-01-01T12:00:00.000Z"
|
|
1856
|
-
}
|
|
1857
|
-
],
|
|
1858
|
-
cursor: null
|
|
1859
|
-
});
|
|
1860
|
-
var errorResponseSchema = z.object({
|
|
1861
|
-
status: z.literal("error"),
|
|
1862
|
-
error: z.object({
|
|
1863
|
-
code: z.string(),
|
|
1864
|
-
message: z.string(),
|
|
1865
|
-
details: z.any().optional()
|
|
1866
|
-
}),
|
|
1867
|
-
meta: z.object({
|
|
1868
|
-
timestamp: z.string()
|
|
1869
|
-
})
|
|
1870
|
-
}).meta({
|
|
1871
|
-
description: "Error response wrapper.",
|
|
1872
|
-
example: {
|
|
1873
|
-
status: "error",
|
|
1874
|
-
error: {
|
|
1875
|
-
code: "VALIDATION_ERROR",
|
|
1876
|
-
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object",
|
|
1877
|
-
details: [
|
|
1878
|
-
{
|
|
1879
|
-
field: "cursor",
|
|
1880
|
-
issue: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1881
|
-
}
|
|
1882
|
-
]
|
|
1883
|
-
},
|
|
1884
|
-
meta: {
|
|
1885
|
-
timestamp: timestampExample
|
|
2228
|
+
if (error !== void 0) {
|
|
2229
|
+
switch (response.status) {
|
|
2230
|
+
case 401:
|
|
2231
|
+
throw new HttpUnauthorizedError();
|
|
2232
|
+
case 403:
|
|
2233
|
+
throw new HttpForbiddenError();
|
|
2234
|
+
case 429:
|
|
2235
|
+
throw new HttpRateLimitError();
|
|
1886
2236
|
}
|
|
2237
|
+
throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {
|
|
2238
|
+
details: JSON.stringify(error)
|
|
2239
|
+
});
|
|
1887
2240
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
},
|
|
1907
|
-
400: {
|
|
1908
|
-
description: "Bad Request",
|
|
1909
|
-
content: {
|
|
1910
|
-
"application/json": {
|
|
1911
|
-
schema: errorResponseSchema
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
},
|
|
1918
|
-
"/v1/obligations": {
|
|
1919
|
-
get: {
|
|
1920
|
-
summary: "Obligations",
|
|
1921
|
-
description: "List obligations with pagination support",
|
|
1922
|
-
tags: ["Obligations"],
|
|
1923
|
-
requestParams: {
|
|
1924
|
-
query: GetObligationsQueryParams
|
|
2241
|
+
const offers = data?.data.map((item) => {
|
|
2242
|
+
const { signature, ...rest } = item;
|
|
2243
|
+
return Offer_exports.fromSnakeCase({
|
|
2244
|
+
...rest,
|
|
2245
|
+
offering: item.offering,
|
|
2246
|
+
maturity: Maturity_exports.from(item.maturity),
|
|
2247
|
+
loan_token: item.loan_token,
|
|
2248
|
+
collaterals: item.collaterals.map((collateral) => ({
|
|
2249
|
+
asset: collateral.asset,
|
|
2250
|
+
oracle: collateral.oracle,
|
|
2251
|
+
lltv: collateral.lltv
|
|
2252
|
+
})),
|
|
2253
|
+
callback: {
|
|
2254
|
+
...item.callback,
|
|
2255
|
+
address: item.callback.address,
|
|
2256
|
+
data: item.callback.data
|
|
1925
2257
|
},
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
content: {
|
|
1930
|
-
"application/json": {
|
|
1931
|
-
schema: ObligationsSuccessResponseSchema
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
},
|
|
1935
|
-
400: {
|
|
1936
|
-
description: "Bad Request",
|
|
1937
|
-
content: {
|
|
1938
|
-
"application/json": {
|
|
1939
|
-
schema: errorResponseSchema
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
},
|
|
1946
|
-
"/v1/health": {
|
|
1947
|
-
get: {
|
|
1948
|
-
summary: "Router status",
|
|
1949
|
-
description: "Retrieve the aggregated status of the router.",
|
|
1950
|
-
tags: ["Health"],
|
|
1951
|
-
responses: {
|
|
1952
|
-
200: {
|
|
1953
|
-
description: "Success",
|
|
1954
|
-
content: {
|
|
1955
|
-
"application/json": {
|
|
1956
|
-
schema: RouterStatusSuccessResponseSchema
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
},
|
|
1963
|
-
"/v1/health/collectors": {
|
|
1964
|
-
get: {
|
|
1965
|
-
summary: "Collectors health",
|
|
1966
|
-
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
1967
|
-
tags: ["Health"],
|
|
1968
|
-
responses: {
|
|
1969
|
-
200: {
|
|
1970
|
-
description: "Success",
|
|
1971
|
-
content: {
|
|
1972
|
-
"application/json": {
|
|
1973
|
-
schema: CollectorsHealthSuccessResponseSchema
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
},
|
|
1980
|
-
"/v1/health/chains": {
|
|
1981
|
-
get: {
|
|
1982
|
-
summary: "Chains health",
|
|
1983
|
-
description: "Retrieve the latest block processed for each chain.",
|
|
1984
|
-
tags: ["Health"],
|
|
1985
|
-
responses: {
|
|
1986
|
-
200: {
|
|
1987
|
-
description: "Success",
|
|
1988
|
-
content: {
|
|
1989
|
-
"application/json": {
|
|
1990
|
-
schema: ChainsHealthSuccessResponseSchema
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
};
|
|
1998
|
-
var OpenApi = createDocument({
|
|
1999
|
-
openapi: "3.1.0",
|
|
2000
|
-
info: {
|
|
2001
|
-
title: "Router API",
|
|
2002
|
-
version: "1.0.0",
|
|
2003
|
-
description: "API for the Morpho Router"
|
|
2004
|
-
},
|
|
2005
|
-
tags: [
|
|
2006
|
-
{
|
|
2007
|
-
name: "Offers"
|
|
2008
|
-
},
|
|
2009
|
-
{
|
|
2010
|
-
name: "Obligations"
|
|
2011
|
-
},
|
|
2012
|
-
{
|
|
2013
|
-
name: "Health"
|
|
2014
|
-
}
|
|
2015
|
-
],
|
|
2016
|
-
servers: [
|
|
2017
|
-
{
|
|
2018
|
-
url: "https://router.morpho.dev",
|
|
2019
|
-
description: "Production server"
|
|
2020
|
-
},
|
|
2021
|
-
{
|
|
2022
|
-
url: "http://localhost:7891",
|
|
2023
|
-
description: "Local development server"
|
|
2024
|
-
}
|
|
2025
|
-
],
|
|
2026
|
-
paths
|
|
2027
|
-
});
|
|
2028
|
-
|
|
2029
|
-
// src/client/Client.ts
|
|
2030
|
-
var Client_exports = {};
|
|
2031
|
-
__export(Client_exports, {
|
|
2032
|
-
HttpForbiddenError: () => HttpForbiddenError,
|
|
2033
|
-
HttpGetApiFailedError: () => HttpGetApiFailedError,
|
|
2034
|
-
HttpRateLimitError: () => HttpRateLimitError,
|
|
2035
|
-
HttpUnauthorizedError: () => HttpUnauthorizedError,
|
|
2036
|
-
InvalidUrlError: () => InvalidUrlError,
|
|
2037
|
-
connect: () => connect,
|
|
2038
|
-
getObligations: () => getObligations,
|
|
2039
|
-
getOffers: () => getOffers
|
|
2040
|
-
});
|
|
2041
|
-
function connect(options) {
|
|
2042
|
-
const u = new URL(options?.url || "https://router.morpho.dev");
|
|
2043
|
-
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
2044
|
-
throw new InvalidUrlError(u.toString());
|
|
2045
|
-
}
|
|
2046
|
-
const headers = options?.headers ?? new Headers();
|
|
2047
|
-
headers.set("Content-Type", "application/json");
|
|
2048
|
-
options?.apiKey !== void 0 ? headers.set("X-API-Key", options.apiKey) : null;
|
|
2049
|
-
const config = {
|
|
2050
|
-
url: u,
|
|
2051
|
-
headers
|
|
2052
|
-
};
|
|
2053
|
-
return {
|
|
2054
|
-
...config,
|
|
2055
|
-
getOffers: (parameters) => getOffers(config, parameters),
|
|
2056
|
-
getObligations: (parameters) => getObligations(config, parameters)
|
|
2057
|
-
};
|
|
2058
|
-
}
|
|
2059
|
-
async function getOffers(config, parameters) {
|
|
2060
|
-
const url = new URL(`${config.url.toString()}v1/offers`);
|
|
2061
|
-
url.searchParams.set("side", parameters.side);
|
|
2062
|
-
url.searchParams.set("obligation_id", parameters.obligationId.toString());
|
|
2063
|
-
if (parameters.cursor) {
|
|
2064
|
-
url.searchParams.set("cursor", parameters.cursor);
|
|
2065
|
-
}
|
|
2066
|
-
if (parameters.limit !== void 0) {
|
|
2067
|
-
url.searchParams.set("limit", parameters.limit.toString());
|
|
2068
|
-
}
|
|
2069
|
-
const { cursor: returnedCursor, data: offers } = await getApi(config, url);
|
|
2070
|
-
const routerOffers = offers.map(Offer_exports.fromSnakeCase);
|
|
2071
|
-
return {
|
|
2072
|
-
cursor: returnedCursor,
|
|
2073
|
-
offers: routerOffers
|
|
2074
|
-
};
|
|
2075
|
-
}
|
|
2076
|
-
async function getObligations(config, parameters) {
|
|
2077
|
-
const url = new URL(`${config.url.toString()}v1/obligations`);
|
|
2078
|
-
if (parameters?.cursor !== void 0) {
|
|
2079
|
-
url.searchParams.set("cursor", parameters.cursor);
|
|
2080
|
-
}
|
|
2081
|
-
if (parameters?.limit !== void 0) {
|
|
2082
|
-
url.searchParams.set("limit", parameters.limit.toString());
|
|
2083
|
-
}
|
|
2084
|
-
const { cursor: returnedCursor, data: items } = await getApi(config, url);
|
|
2085
|
-
const obligations = items.map((item) => {
|
|
2086
|
-
const obligation = Obligation_exports.fromSnakeCase(item);
|
|
2087
|
-
const { obligationId: _, ...returned } = {
|
|
2088
|
-
id: () => Obligation_exports.id(obligation),
|
|
2089
|
-
...obligation,
|
|
2090
|
-
...Quote_exports.fromSnakeCase({ obligation_id: item.id, ask: item.ask, bid: item.bid })
|
|
2091
|
-
};
|
|
2092
|
-
return returned;
|
|
2093
|
-
});
|
|
2258
|
+
...signature !== null ? { signature: item.signature } : void 0
|
|
2259
|
+
});
|
|
2260
|
+
}) ?? [];
|
|
2094
2261
|
return {
|
|
2095
|
-
cursor:
|
|
2096
|
-
|
|
2262
|
+
cursor: data?.cursor ?? null,
|
|
2263
|
+
offers
|
|
2097
2264
|
};
|
|
2098
2265
|
}
|
|
2099
|
-
async function
|
|
2100
|
-
const
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
action = "get_obligations";
|
|
2108
|
-
break;
|
|
2109
|
-
default:
|
|
2110
|
-
throw new HttpGetApiFailedError("Unknown endpoint", {
|
|
2111
|
-
details: `Unsupported path: ${pathname}`
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2114
|
-
const schemaParseResult = safeParse(action, Object.fromEntries(url.searchParams));
|
|
2115
|
-
if (!schemaParseResult.success) {
|
|
2116
|
-
throw new HttpGetApiFailedError(`Invalid URL parameters`, {
|
|
2117
|
-
details: schemaParseResult.error.issues[0]?.message
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
const response = await fetch(url.toString(), {
|
|
2121
|
-
method: "GET",
|
|
2122
|
-
headers: config.headers
|
|
2266
|
+
async function getObligations(apiClient, parameters) {
|
|
2267
|
+
const { data, error, response } = await apiClient.GET("/v1/obligations", {
|
|
2268
|
+
params: {
|
|
2269
|
+
query: {
|
|
2270
|
+
cursor: parameters?.cursor,
|
|
2271
|
+
limit: parameters?.limit
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2123
2274
|
});
|
|
2124
|
-
if (
|
|
2275
|
+
if (error !== void 0) {
|
|
2125
2276
|
switch (response.status) {
|
|
2126
2277
|
case 401:
|
|
2127
2278
|
throw new HttpUnauthorizedError();
|
|
@@ -2131,10 +2282,31 @@ async function getApi(config, url) {
|
|
|
2131
2282
|
throw new HttpRateLimitError();
|
|
2132
2283
|
}
|
|
2133
2284
|
throw new HttpGetApiFailedError(`GET request returned ${response.status}`, {
|
|
2134
|
-
details:
|
|
2285
|
+
details: JSON.stringify(error)
|
|
2135
2286
|
});
|
|
2136
2287
|
}
|
|
2137
|
-
|
|
2288
|
+
const obligations = data?.data.map((item) => {
|
|
2289
|
+
const obligation = Obligation_exports.fromSnakeCase({
|
|
2290
|
+
chain_id: item.chain_id,
|
|
2291
|
+
loan_token: item.loan_token,
|
|
2292
|
+
collaterals: item.collaterals.map((collateral) => ({
|
|
2293
|
+
asset: collateral.asset,
|
|
2294
|
+
oracle: collateral.oracle,
|
|
2295
|
+
lltv: collateral.lltv
|
|
2296
|
+
})),
|
|
2297
|
+
maturity: Maturity_exports.from(item.maturity)
|
|
2298
|
+
});
|
|
2299
|
+
const { obligationId: _, ...returned } = {
|
|
2300
|
+
id: () => Obligation_exports.id(obligation),
|
|
2301
|
+
...obligation,
|
|
2302
|
+
...Quote_exports.fromSnakeCase({ obligation_id: item.id, ask: item.ask, bid: item.bid })
|
|
2303
|
+
};
|
|
2304
|
+
return returned;
|
|
2305
|
+
}) ?? [];
|
|
2306
|
+
return {
|
|
2307
|
+
cursor: data?.cursor ?? null,
|
|
2308
|
+
obligations
|
|
2309
|
+
};
|
|
2138
2310
|
}
|
|
2139
2311
|
var InvalidUrlError = class extends BaseError {
|
|
2140
2312
|
constructor(url) {
|
|
@@ -2177,13 +2349,21 @@ var HttpGetApiFailedError = class extends BaseError {
|
|
|
2177
2349
|
}
|
|
2178
2350
|
};
|
|
2179
2351
|
|
|
2180
|
-
// src/
|
|
2181
|
-
var
|
|
2182
|
-
__export(
|
|
2183
|
-
|
|
2352
|
+
// src/gatekeeper/Gate.ts
|
|
2353
|
+
var Gate_exports = {};
|
|
2354
|
+
__export(Gate_exports, {
|
|
2355
|
+
batch: () => batch2,
|
|
2356
|
+
run: () => run,
|
|
2357
|
+
single: () => single
|
|
2184
2358
|
});
|
|
2359
|
+
function single(name, run2) {
|
|
2360
|
+
return { kind: "single", name, run: run2 };
|
|
2361
|
+
}
|
|
2362
|
+
function batch2(name, run2) {
|
|
2363
|
+
return { kind: "batch", name, run: run2 };
|
|
2364
|
+
}
|
|
2185
2365
|
async function run(parameters) {
|
|
2186
|
-
const { items, rules,
|
|
2366
|
+
const { items, rules, chunkSize } = parameters;
|
|
2187
2367
|
const issues = [];
|
|
2188
2368
|
let validItems = items.slice();
|
|
2189
2369
|
for (const rule of rules) {
|
|
@@ -2192,7 +2372,7 @@ async function run(parameters) {
|
|
|
2192
2372
|
if (rule.kind === "single") {
|
|
2193
2373
|
for (let i = 0; i < validItems.length; i++) {
|
|
2194
2374
|
const item = validItems[i];
|
|
2195
|
-
const issue = await rule.run(item
|
|
2375
|
+
const issue = await rule.run(item);
|
|
2196
2376
|
if (issue) {
|
|
2197
2377
|
issues.push({ ...issue, ruleName: rule.name, item });
|
|
2198
2378
|
indicesToRemove.add(i);
|
|
@@ -2200,7 +2380,7 @@ async function run(parameters) {
|
|
|
2200
2380
|
}
|
|
2201
2381
|
} else if (rule.kind === "batch") {
|
|
2202
2382
|
const exec = async (slice, offset) => {
|
|
2203
|
-
const map = await rule.run(slice
|
|
2383
|
+
const map = await rule.run(slice);
|
|
2204
2384
|
for (let i = 0; i < slice.length; i++) {
|
|
2205
2385
|
const issue = map.get(i);
|
|
2206
2386
|
if (issue !== void 0) {
|
|
@@ -2224,157 +2404,265 @@ async function run(parameters) {
|
|
|
2224
2404
|
};
|
|
2225
2405
|
}
|
|
2226
2406
|
|
|
2227
|
-
// src/
|
|
2228
|
-
var
|
|
2229
|
-
__export(
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2407
|
+
// src/gatekeeper/GateConfig.ts
|
|
2408
|
+
var GateConfig_exports = {};
|
|
2409
|
+
__export(GateConfig_exports, {
|
|
2410
|
+
assets: () => assets,
|
|
2411
|
+
configs: () => configs,
|
|
2412
|
+
getCallback: () => getCallback,
|
|
2413
|
+
getCallbackAddresses: () => getCallbackAddresses,
|
|
2414
|
+
getCallbackType: () => getCallbackType,
|
|
2415
|
+
getCallbackTypeAddresses: () => getCallbackTypeAddresses
|
|
2233
2416
|
});
|
|
2234
|
-
function
|
|
2235
|
-
return
|
|
2417
|
+
function getCallback(chain2, type) {
|
|
2418
|
+
return configs[chain2].callbacks?.find((c) => c.type === type);
|
|
2236
2419
|
}
|
|
2237
|
-
function
|
|
2238
|
-
return
|
|
2420
|
+
function getCallbackType(chain2, address) {
|
|
2421
|
+
return configs[chain2].callbacks?.find(
|
|
2422
|
+
(c) => c.type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */ && c.addresses.includes(address?.toLowerCase())
|
|
2423
|
+
)?.type;
|
|
2239
2424
|
}
|
|
2240
|
-
function
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
"
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
"
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2425
|
+
function getCallbackTypeAddresses(chain2, type) {
|
|
2426
|
+
if (type === "buy_with_empty_callback" /* BuyWithEmptyCallback */) {
|
|
2427
|
+
return [];
|
|
2428
|
+
}
|
|
2429
|
+
const match = configs[chain2].callbacks?.find((c) => c.type === type);
|
|
2430
|
+
return match && "addresses" in match ? match.addresses : [];
|
|
2431
|
+
}
|
|
2432
|
+
var getCallbackAddresses = (chain2) => {
|
|
2433
|
+
return configs[chain2].callbacks?.filter((c) => c.type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */).flatMap((c) => c.addresses) ?? [];
|
|
2434
|
+
};
|
|
2435
|
+
var assets = {
|
|
2436
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
2437
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
2438
|
+
// USDC
|
|
2439
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
2440
|
+
// DAI
|
|
2441
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
2442
|
+
// WETH
|
|
2443
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
2444
|
+
// WBTC
|
|
2445
|
+
],
|
|
2446
|
+
[ChainId.BASE.toString()]: [
|
|
2447
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2448
|
+
// USDC
|
|
2449
|
+
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
|
|
2450
|
+
// DAI
|
|
2451
|
+
"0x4200000000000000000000000000000000000006",
|
|
2452
|
+
// WETH
|
|
2453
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
2454
|
+
// WBTC
|
|
2455
|
+
],
|
|
2456
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
2457
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
2458
|
+
// USDC
|
|
2459
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
2460
|
+
// DAI
|
|
2461
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
2462
|
+
// WETH
|
|
2463
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
2464
|
+
// WBTC
|
|
2465
|
+
],
|
|
2466
|
+
[ChainId.ANVIL.toString()]: [
|
|
2467
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
2468
|
+
// USDC
|
|
2469
|
+
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
2470
|
+
// DAI
|
|
2471
|
+
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
2472
|
+
// WETH
|
|
2473
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
2474
|
+
// WBTC
|
|
2475
|
+
]
|
|
2476
|
+
};
|
|
2477
|
+
var configs = {
|
|
2478
|
+
ethereum: {
|
|
2479
|
+
callbacks: [
|
|
2480
|
+
{
|
|
2481
|
+
type: "buy_vault_v1_callback" /* BuyVaultV1Callback */,
|
|
2482
|
+
addresses: [
|
|
2483
|
+
"0x3333333333333333333333333333333333333333",
|
|
2484
|
+
"0x4444444444444444444444444444444444444444"
|
|
2485
|
+
],
|
|
2486
|
+
vaultFactories: [
|
|
2487
|
+
"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
2488
|
+
//v1.0
|
|
2489
|
+
"0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
2490
|
+
//v1.1
|
|
2491
|
+
]
|
|
2492
|
+
},
|
|
2493
|
+
{
|
|
2494
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
2495
|
+
addresses: [
|
|
2496
|
+
"0x1111111111111111111111111111111111111111",
|
|
2497
|
+
"0x2222222222222222222222222222222222222222"
|
|
2498
|
+
]
|
|
2499
|
+
},
|
|
2500
|
+
{ type: "buy_with_empty_callback" /* BuyWithEmptyCallback */ }
|
|
2501
|
+
],
|
|
2502
|
+
maturities: ["end_of_month" /* EndOfMonth */, "end_of_next_month" /* EndOfNextMonth */]
|
|
2503
|
+
},
|
|
2504
|
+
base: {
|
|
2505
|
+
callbacks: [
|
|
2506
|
+
{
|
|
2507
|
+
type: "buy_vault_v1_callback" /* BuyVaultV1Callback */,
|
|
2508
|
+
addresses: [
|
|
2509
|
+
"0x3333333333333333333333333333333333333333",
|
|
2510
|
+
"0x4444444444444444444444444444444444444444"
|
|
2511
|
+
],
|
|
2512
|
+
vaultFactories: [
|
|
2513
|
+
"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
2514
|
+
//v1.0
|
|
2515
|
+
"0xFf62A7c278C62eD665133147129245053Bbf5918"
|
|
2516
|
+
//v1.1
|
|
2517
|
+
]
|
|
2518
|
+
},
|
|
2519
|
+
{
|
|
2520
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
2521
|
+
addresses: [
|
|
2522
|
+
"0x1111111111111111111111111111111111111111",
|
|
2523
|
+
"0x2222222222222222222222222222222222222222"
|
|
2524
|
+
]
|
|
2525
|
+
},
|
|
2526
|
+
{ type: "buy_with_empty_callback" /* BuyWithEmptyCallback */ }
|
|
2527
|
+
],
|
|
2528
|
+
maturities: ["end_of_month" /* EndOfMonth */, "end_of_next_month" /* EndOfNextMonth */]
|
|
2529
|
+
},
|
|
2530
|
+
"ethereum-virtual-testnet": {
|
|
2531
|
+
callbacks: [
|
|
2532
|
+
{
|
|
2533
|
+
type: "buy_vault_v1_callback" /* BuyVaultV1Callback */,
|
|
2534
|
+
addresses: [
|
|
2535
|
+
"0x3333333333333333333333333333333333333333",
|
|
2536
|
+
"0x4444444444444444444444444444444444444444"
|
|
2537
|
+
],
|
|
2538
|
+
vaultFactories: [
|
|
2539
|
+
"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
2540
|
+
//v1.0
|
|
2541
|
+
"0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
2542
|
+
//v1.1
|
|
2543
|
+
]
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
2547
|
+
addresses: [
|
|
2548
|
+
"0x1111111111111111111111111111111111111111",
|
|
2549
|
+
"0x2222222222222222222222222222222222222222"
|
|
2550
|
+
]
|
|
2551
|
+
},
|
|
2552
|
+
{ type: "buy_with_empty_callback" /* BuyWithEmptyCallback */ }
|
|
2553
|
+
],
|
|
2554
|
+
maturities: ["end_of_month" /* EndOfMonth */, "end_of_next_month" /* EndOfNextMonth */]
|
|
2555
|
+
},
|
|
2556
|
+
anvil: {
|
|
2557
|
+
callbacks: [
|
|
2558
|
+
{
|
|
2559
|
+
type: "buy_vault_v1_callback" /* BuyVaultV1Callback */,
|
|
2560
|
+
addresses: [
|
|
2561
|
+
"0x3333333333333333333333333333333333333333",
|
|
2562
|
+
"0x4444444444444444444444444444444444444444"
|
|
2563
|
+
],
|
|
2564
|
+
vaultFactories: [
|
|
2565
|
+
"0xA9c3D3a366466Fa809d1Ae982Fb2c46E5fC41101",
|
|
2566
|
+
//v1.0
|
|
2567
|
+
"0x1897A8997241C1cD4bD0698647e4EB7213535c24"
|
|
2568
|
+
//v1.1
|
|
2569
|
+
]
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
type: "sell_erc20_callback" /* SellERC20Callback */,
|
|
2573
|
+
addresses: [
|
|
2574
|
+
"0x1111111111111111111111111111111111111111",
|
|
2575
|
+
"0x2222222222222222222222222222222222222222"
|
|
2576
|
+
]
|
|
2577
|
+
},
|
|
2578
|
+
{ type: "buy_with_empty_callback" /* BuyWithEmptyCallback */ }
|
|
2579
|
+
],
|
|
2580
|
+
maturities: ["end_of_month" /* EndOfMonth */, "end_of_next_month" /* EndOfNextMonth */]
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2584
|
+
// src/gatekeeper/Gatekeeper.ts
|
|
2585
|
+
var Gatekeeper_exports = {};
|
|
2586
|
+
__export(Gatekeeper_exports, {
|
|
2587
|
+
create: () => create
|
|
2588
|
+
});
|
|
2589
|
+
function create(parameters) {
|
|
2590
|
+
return {
|
|
2591
|
+
isAllowed: async (offers) => {
|
|
2592
|
+
return await run({
|
|
2593
|
+
items: offers,
|
|
2594
|
+
rules: parameters.rules
|
|
2595
|
+
});
|
|
2287
2596
|
}
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
// src/gatekeeper/Rules.ts
|
|
2601
|
+
var Rules_exports = {};
|
|
2602
|
+
__export(Rules_exports, {
|
|
2603
|
+
callback: () => callback,
|
|
2604
|
+
chain: () => chain,
|
|
2605
|
+
maturity: () => maturity,
|
|
2606
|
+
token: () => token,
|
|
2607
|
+
validity: () => validity
|
|
2608
|
+
});
|
|
2609
|
+
function validity(parameters) {
|
|
2610
|
+
const { chain: chain2, client } = parameters;
|
|
2611
|
+
const sellErc20CallbackInvalid = single("sell_erc20_callback_invalid", (offer) => {
|
|
2612
|
+
const callbackType = getCallbackType(chain2.name, offer.callback.address);
|
|
2613
|
+
if (callbackType !== Callback_exports.CallbackType.SellERC20Callback) {
|
|
2614
|
+
return;
|
|
2303
2615
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
(offer, _) => {
|
|
2308
|
-
if (!offer.buy && offer.callback.data !== "0x") {
|
|
2309
|
-
try {
|
|
2310
|
-
const decoded = Callback_exports.decodeSellERC20Callback(offer.callback.data);
|
|
2311
|
-
if (decoded.length === 0) {
|
|
2312
|
-
return { message: "Sell offer callback data must include at least one collateral." };
|
|
2313
|
-
}
|
|
2314
|
-
} catch (_2) {
|
|
2315
|
-
return { message: "Sell offer callback data cannot be decoded." };
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2616
|
+
const decoded = Callback_exports.decode(callbackType, offer.callback.data);
|
|
2617
|
+
if (decoded.length === 0) {
|
|
2618
|
+
return { message: "Callback data cannot be decoded or is empty." };
|
|
2318
2619
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
if (
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
offer.collaterals.map((c) => c.asset.toLowerCase())
|
|
2328
|
-
);
|
|
2329
|
-
for (const { collateral } of decoded) {
|
|
2330
|
-
if (!offerCollaterals.has(collateral.toLowerCase())) {
|
|
2331
|
-
return { message: "Sell callback collateral is not part of offer collaterals." };
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
} catch (_2) {
|
|
2335
|
-
}
|
|
2620
|
+
if (callbackType === Callback_exports.CallbackType.SellERC20Callback) {
|
|
2621
|
+
const offerCollaterals = new Set(
|
|
2622
|
+
offer.collaterals.map((c) => c.asset.toLowerCase())
|
|
2623
|
+
);
|
|
2624
|
+
if (decoded.length !== offer.collaterals.length) {
|
|
2625
|
+
return {
|
|
2626
|
+
message: `Sell callback collateral length mismatch. Expected ${offer.collaterals.length}, got ${decoded.length}.`
|
|
2627
|
+
};
|
|
2336
2628
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
"buy_offers_callback_data_invalid",
|
|
2341
|
-
(offer, _) => {
|
|
2342
|
-
if (offer.buy && offer.callback.data !== "0x") {
|
|
2343
|
-
try {
|
|
2344
|
-
const decoded = Callback_exports.decodeBuyVaultV1Callback(offer.callback.data);
|
|
2345
|
-
if (decoded.length === 0) {
|
|
2346
|
-
return { message: "Buy offer callback data must include at least one vault." };
|
|
2347
|
-
}
|
|
2348
|
-
} catch (_2) {
|
|
2349
|
-
return { message: "Buy offer callback data cannot be decoded." };
|
|
2629
|
+
for (const { collateral } of decoded) {
|
|
2630
|
+
if (!offerCollaterals.has(collateral.toLowerCase())) {
|
|
2631
|
+
return { message: "Sell callback collateral is not part of offer collaterals." };
|
|
2350
2632
|
}
|
|
2351
2633
|
}
|
|
2352
2634
|
}
|
|
2353
|
-
);
|
|
2635
|
+
});
|
|
2354
2636
|
const buyCallbackVaultInvalid = batch2(
|
|
2355
2637
|
"buy_offers_callback_vault_invalid",
|
|
2356
|
-
async (offers
|
|
2638
|
+
async (offers) => {
|
|
2357
2639
|
const validationIssues = /* @__PURE__ */ new Map();
|
|
2358
2640
|
const offersByVaultAddress = /* @__PURE__ */ new Map();
|
|
2359
2641
|
for (let i = 0; i < offers.length; i++) {
|
|
2360
2642
|
const offer = offers[i];
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2643
|
+
const callbackType = getCallbackType(chain2.name, offer.callback.address);
|
|
2644
|
+
if (callbackType !== Callback_exports.CallbackType.BuyVaultV1Callback) {
|
|
2645
|
+
continue;
|
|
2646
|
+
}
|
|
2647
|
+
try {
|
|
2648
|
+
const callbackVaults = Callback_exports.decodeBuyVaultV1Callback(offer.callback.data);
|
|
2649
|
+
for (const { vault } of callbackVaults) {
|
|
2650
|
+
const normalizedVaultAddress = vault.toLowerCase();
|
|
2651
|
+
if (!offersByVaultAddress.has(normalizedVaultAddress)) {
|
|
2652
|
+
offersByVaultAddress.set(normalizedVaultAddress, []);
|
|
2370
2653
|
}
|
|
2371
|
-
|
|
2654
|
+
offersByVaultAddress.get(normalizedVaultAddress).push({ index: i, offer });
|
|
2372
2655
|
}
|
|
2656
|
+
} catch (_) {
|
|
2373
2657
|
}
|
|
2374
2658
|
}
|
|
2375
2659
|
const uniqueVaultAddresses = Array.from(offersByVaultAddress.keys());
|
|
2376
2660
|
if (uniqueVaultAddresses.length === 0) return validationIssues;
|
|
2377
|
-
const
|
|
2661
|
+
const allowedFactories = getCallback(
|
|
2662
|
+
chain2.name,
|
|
2663
|
+
Callback_exports.CallbackType.BuyVaultV1Callback
|
|
2664
|
+
)?.vaultFactories.map((f) => f.toLowerCase());
|
|
2665
|
+
if (!allowedFactories) return validationIssues;
|
|
2378
2666
|
const multicallContracts = [];
|
|
2379
2667
|
for (const vaultAddress of uniqueVaultAddresses) {
|
|
2380
2668
|
multicallContracts.push({
|
|
@@ -2382,7 +2670,7 @@ function morpho() {
|
|
|
2382
2670
|
abi: Abi_exports.ERC4626,
|
|
2383
2671
|
functionName: "asset"
|
|
2384
2672
|
});
|
|
2385
|
-
for (const factoryAddress of
|
|
2673
|
+
for (const factoryAddress of allowedFactories) {
|
|
2386
2674
|
multicallContracts.push({
|
|
2387
2675
|
address: factoryAddress,
|
|
2388
2676
|
abi: Abi_exports.MetaMorphoFactory,
|
|
@@ -2397,7 +2685,7 @@ function morpho() {
|
|
|
2397
2685
|
});
|
|
2398
2686
|
const vaultAssetByAddress = /* @__PURE__ */ new Map();
|
|
2399
2687
|
const registeredVaults = /* @__PURE__ */ new Set();
|
|
2400
|
-
const numberOfFactories =
|
|
2688
|
+
const numberOfFactories = allowedFactories.length;
|
|
2401
2689
|
let resultIndex = 0;
|
|
2402
2690
|
for (const vaultAddress of uniqueVaultAddresses) {
|
|
2403
2691
|
const assetCallResult = multicallResults[resultIndex++];
|
|
@@ -2456,30 +2744,61 @@ function morpho() {
|
|
|
2456
2744
|
return validationIssues;
|
|
2457
2745
|
}
|
|
2458
2746
|
);
|
|
2459
|
-
const
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
return {
|
|
2463
|
-
message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}`
|
|
2464
|
-
};
|
|
2747
|
+
const expiry = single("expiry", (offer) => {
|
|
2748
|
+
if (offer.expiry < Math.floor(Date.now() / 1e3)) {
|
|
2749
|
+
return { message: "Expiry mismatch" };
|
|
2465
2750
|
}
|
|
2466
2751
|
});
|
|
2467
|
-
return [
|
|
2468
|
-
chainId,
|
|
2469
|
-
loanToken,
|
|
2470
|
-
expiry,
|
|
2471
|
-
maturity,
|
|
2472
|
-
// note: callback rules should be the last ones, since they do not mean that the offer is forever invalid
|
|
2473
|
-
// integrators should be able to choose if they want to keep the offer or not
|
|
2474
|
-
sellEmptyCallback,
|
|
2475
|
-
buyNonEmptyCallback,
|
|
2476
|
-
sellNonWhitelistedCallback,
|
|
2477
|
-
sellCallbackDataInvalid,
|
|
2478
|
-
sellCallbackCollateralInvalid,
|
|
2479
|
-
buyCallbackDataInvalid,
|
|
2480
|
-
buyCallbackVaultInvalid
|
|
2481
|
-
];
|
|
2752
|
+
return [expiry, sellErc20CallbackInvalid, buyCallbackVaultInvalid];
|
|
2482
2753
|
}
|
|
2754
|
+
var chain = ({ chain: chain2 }) => single("chain_id", (offer) => {
|
|
2755
|
+
if (chain2.id !== offer.chainId) {
|
|
2756
|
+
return {
|
|
2757
|
+
message: `Chain ID ${offer.chainId} is not the same as the chain ID in the context (${chain2.id})`
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
var maturity = ({ maturities }) => single("maturity", (offer) => {
|
|
2762
|
+
const allowedMaturities = maturities.map((m) => Maturity_exports.from(m));
|
|
2763
|
+
if (!allowedMaturities.includes(offer.maturity)) {
|
|
2764
|
+
return {
|
|
2765
|
+
message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}`
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2768
|
+
});
|
|
2769
|
+
var callback = ({
|
|
2770
|
+
callbacks,
|
|
2771
|
+
allowedAddresses
|
|
2772
|
+
}) => single("callback", (offer) => {
|
|
2773
|
+
if (Callback_exports.isEmptyCallback(offer) && offer.buy && !callbacks?.find((c) => c === Callback_exports.CallbackType.BuyWithEmptyCallback)) {
|
|
2774
|
+
return {
|
|
2775
|
+
message: "Buy offers with empty callback not allowed."
|
|
2776
|
+
};
|
|
2777
|
+
}
|
|
2778
|
+
if (Callback_exports.isEmptyCallback(offer) && !offer.buy) {
|
|
2779
|
+
return {
|
|
2780
|
+
message: "Sell offers require a non-empty callback."
|
|
2781
|
+
};
|
|
2782
|
+
}
|
|
2783
|
+
if (!Callback_exports.isEmptyCallback(offer)) {
|
|
2784
|
+
if (!allowedAddresses.includes(offer.callback.address?.toLowerCase())) {
|
|
2785
|
+
return {
|
|
2786
|
+
message: `Callback address ${offer.callback.address} is not allowed.`
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
});
|
|
2791
|
+
var token = ({ assets: assets2 }) => single("token", (offer) => {
|
|
2792
|
+
const allowedAssets = assets2?.map((asset) => asset.toLowerCase());
|
|
2793
|
+
if (!allowedAssets || allowedAssets.length === 0) return { message: "No allowed assets" };
|
|
2794
|
+
if (!allowedAssets.includes(offer.loanToken.toLowerCase()))
|
|
2795
|
+
return { message: "Loan token is not allowed" };
|
|
2796
|
+
if (offer.collaterals.some(
|
|
2797
|
+
(collateral) => !allowedAssets.includes(collateral.asset.toLowerCase())
|
|
2798
|
+
))
|
|
2799
|
+
return { message: "Collateral is not allowed" };
|
|
2800
|
+
return void 0;
|
|
2801
|
+
});
|
|
2483
2802
|
|
|
2484
2803
|
// src/mempool/MempoolClient.ts
|
|
2485
2804
|
var MempoolClient_exports = {};
|
|
@@ -2488,7 +2807,7 @@ __export(MempoolClient_exports, {
|
|
|
2488
2807
|
});
|
|
2489
2808
|
var DEFAULT_BATCH_SIZE2 = 100;
|
|
2490
2809
|
var DEFAULT_BLOCK_WINDOW2 = 100;
|
|
2491
|
-
function
|
|
2810
|
+
function from10(parameters) {
|
|
2492
2811
|
const config = {
|
|
2493
2812
|
client: parameters.client,
|
|
2494
2813
|
mempoolAddress: parameters.mempoolAddress,
|
|
@@ -2497,24 +2816,24 @@ function from9(parameters) {
|
|
|
2497
2816
|
return {
|
|
2498
2817
|
add: (parameters2) => add(config, parameters2),
|
|
2499
2818
|
get: (parameters2) => get(config, parameters2),
|
|
2500
|
-
watch: (parameters2) => watch(config, parameters2),
|
|
2501
2819
|
stream: (parameters2) => streamOffers(config, parameters2)
|
|
2502
2820
|
};
|
|
2503
2821
|
}
|
|
2504
|
-
async function add(config,
|
|
2505
|
-
const offer = Offer_exports.from(parameters.offer);
|
|
2822
|
+
async function add(config, offers) {
|
|
2506
2823
|
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
2824
|
+
const tree = Tree_exports.from(offers.map((o) => Offer_exports.from(o)));
|
|
2507
2825
|
const chainId = await getChainId(config.client);
|
|
2508
|
-
|
|
2509
|
-
|
|
2826
|
+
for (const offer of tree.offers) {
|
|
2827
|
+
if (BigInt(chainId) !== offer.chainId)
|
|
2828
|
+
throw new ChainIdMismatchError(offer.chainId, BigInt(chainId));
|
|
2829
|
+
}
|
|
2510
2830
|
try {
|
|
2511
|
-
|
|
2831
|
+
return await config.client.sendTransaction({
|
|
2512
2832
|
chain: config.client.chain,
|
|
2513
2833
|
account: config.client.account,
|
|
2514
2834
|
to: config.mempoolAddress,
|
|
2515
|
-
data:
|
|
2835
|
+
data: Tree_exports.encode(tree)
|
|
2516
2836
|
});
|
|
2517
|
-
return { offer, txHash: tx };
|
|
2518
2837
|
} catch (error) {
|
|
2519
2838
|
throw new ViemClientError(error instanceof Error ? error.message : "Unknown error");
|
|
2520
2839
|
}
|
|
@@ -2524,40 +2843,17 @@ async function* get(config, parameters) {
|
|
|
2524
2843
|
loanToken,
|
|
2525
2844
|
blockNumberGte,
|
|
2526
2845
|
blockNumberLte,
|
|
2527
|
-
order = "desc",
|
|
2846
|
+
order: order2 = "desc",
|
|
2528
2847
|
options: { maxBatchSize = DEFAULT_BATCH_SIZE2 } = {}
|
|
2529
2848
|
} = parameters || {};
|
|
2530
2849
|
yield* streamOffers(config, {
|
|
2531
2850
|
loanToken,
|
|
2532
|
-
order,
|
|
2851
|
+
order: order2,
|
|
2533
2852
|
blockNumberGte,
|
|
2534
2853
|
blockNumberLte,
|
|
2535
2854
|
options: { maxBatchSize, blockWindow: config.blockWindow }
|
|
2536
2855
|
});
|
|
2537
2856
|
}
|
|
2538
|
-
function watch(config, parameters) {
|
|
2539
|
-
const {
|
|
2540
|
-
loanToken,
|
|
2541
|
-
lastSyncedBlock,
|
|
2542
|
-
polling: { interval = 3e4, maxBatchSize = DEFAULT_BATCH_SIZE2 } = {},
|
|
2543
|
-
onOffers
|
|
2544
|
-
} = parameters;
|
|
2545
|
-
return poll(
|
|
2546
|
-
async () => {
|
|
2547
|
-
const blockNumberGte = await lastSyncedBlock();
|
|
2548
|
-
const stream = streamOffers(config, {
|
|
2549
|
-
loanToken,
|
|
2550
|
-
order: "asc",
|
|
2551
|
-
blockNumberGte,
|
|
2552
|
-
options: { maxBatchSize, blockWindow: config.blockWindow }
|
|
2553
|
-
});
|
|
2554
|
-
for await (const { offers, blockNumber } of stream) {
|
|
2555
|
-
await onOffers(offers, blockNumber);
|
|
2556
|
-
}
|
|
2557
|
-
},
|
|
2558
|
-
{ interval }
|
|
2559
|
-
);
|
|
2560
|
-
}
|
|
2561
2857
|
var chainIdCache = /* @__PURE__ */ new Map();
|
|
2562
2858
|
var getChainId = async (client) => {
|
|
2563
2859
|
if (chainIdCache.has(client.uid)) return chainIdCache.get(client.uid);
|
|
@@ -2570,7 +2866,7 @@ async function* streamOffers(config, parameters) {
|
|
|
2570
2866
|
loanToken,
|
|
2571
2867
|
blockNumberGte,
|
|
2572
2868
|
blockNumberLte,
|
|
2573
|
-
order = "desc",
|
|
2869
|
+
order: order2 = "desc",
|
|
2574
2870
|
options: { maxBatchSize = DEFAULT_BATCH_SIZE2, blockWindow = config.blockWindow } = {}
|
|
2575
2871
|
} = parameters;
|
|
2576
2872
|
const stream = Chain_exports.streamLogs({
|
|
@@ -2584,28 +2880,29 @@ async function* streamOffers(config, parameters) {
|
|
|
2584
2880
|
},
|
|
2585
2881
|
blockNumberGte,
|
|
2586
2882
|
blockNumberLte,
|
|
2587
|
-
order,
|
|
2883
|
+
order: order2,
|
|
2588
2884
|
options: { maxBatchSize, blockWindow }
|
|
2589
2885
|
});
|
|
2590
|
-
let blockNumber =
|
|
2886
|
+
let blockNumber = order2 === "asc" ? blockNumberGte : blockNumberLte;
|
|
2591
2887
|
for await (const { logs, blockNumber: newBlockNumber } of stream) {
|
|
2592
2888
|
blockNumber = newBlockNumber;
|
|
2593
2889
|
if (logs.length === 0) break;
|
|
2594
|
-
|
|
2890
|
+
const offers = [];
|
|
2891
|
+
for (const log of logs) {
|
|
2892
|
+
if (!log) continue;
|
|
2595
2893
|
const [payload] = decodeAbiParameters([{ type: "bytes" }], log.data);
|
|
2596
2894
|
try {
|
|
2597
|
-
|
|
2895
|
+
const tree = Tree_exports.decode(payload);
|
|
2896
|
+
for (const offer of tree.offers) {
|
|
2897
|
+
if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
|
|
2898
|
+
offers.push({ ...offer, blockNumber: Number(log.blockNumber) });
|
|
2899
|
+
}
|
|
2598
2900
|
} catch (_) {
|
|
2599
|
-
return null;
|
|
2600
2901
|
}
|
|
2601
|
-
}
|
|
2602
|
-
if (
|
|
2603
|
-
offersAndBlockNumbers = offersAndBlockNumbers.filter(
|
|
2604
|
-
(o) => o.offer.loanToken.toLowerCase() === loanToken.toLowerCase()
|
|
2605
|
-
);
|
|
2606
|
-
if (offersAndBlockNumbers.length === 0) continue;
|
|
2902
|
+
}
|
|
2903
|
+
if (offers.length === 0) continue;
|
|
2607
2904
|
yield {
|
|
2608
|
-
offers
|
|
2905
|
+
offers,
|
|
2609
2906
|
blockNumber
|
|
2610
2907
|
};
|
|
2611
2908
|
}
|
|
@@ -2633,9 +2930,129 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
2633
2930
|
|
|
2634
2931
|
// src/mempool/MempoolClient.ts
|
|
2635
2932
|
function connect2(parameters) {
|
|
2636
|
-
return
|
|
2933
|
+
return from10(parameters);
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
// src/utils/index.ts
|
|
2937
|
+
var utils_exports = {};
|
|
2938
|
+
__export(utils_exports, {
|
|
2939
|
+
BaseError: () => BaseError,
|
|
2940
|
+
Time: () => time_exports,
|
|
2941
|
+
batch: () => batch,
|
|
2942
|
+
batchMulticall: () => batchMulticall,
|
|
2943
|
+
fromSnakeCase: () => fromSnakeCase,
|
|
2944
|
+
lazy: () => lazy,
|
|
2945
|
+
max: () => max,
|
|
2946
|
+
min: () => min,
|
|
2947
|
+
poll: () => poll,
|
|
2948
|
+
retry: () => retry,
|
|
2949
|
+
stringifyBigint: () => stringifyBigint,
|
|
2950
|
+
toSnakeCase: () => toSnakeCase,
|
|
2951
|
+
wait: () => wait
|
|
2952
|
+
});
|
|
2953
|
+
|
|
2954
|
+
// src/utils/retry.ts
|
|
2955
|
+
var retry = async (fn, attempts = 3, delayMs = 50) => {
|
|
2956
|
+
let lastErr;
|
|
2957
|
+
for (let i = 0; i < attempts; i++) {
|
|
2958
|
+
try {
|
|
2959
|
+
return await fn();
|
|
2960
|
+
} catch (err) {
|
|
2961
|
+
lastErr = err;
|
|
2962
|
+
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
throw lastErr;
|
|
2966
|
+
};
|
|
2967
|
+
|
|
2968
|
+
// src/utils/batchMulticall.ts
|
|
2969
|
+
async function batchMulticall(parameters) {
|
|
2970
|
+
const { client, calls, batchSize, retryAttempts, retryDelayMs, blockNumber } = parameters;
|
|
2971
|
+
const results = [];
|
|
2972
|
+
for (const callsBatch of batch(calls, batchSize)) {
|
|
2973
|
+
const batchResults = await retry(
|
|
2974
|
+
() => client.multicall({
|
|
2975
|
+
allowFailure: false,
|
|
2976
|
+
contracts: callsBatch,
|
|
2977
|
+
...blockNumber ? { blockNumber } : {}
|
|
2978
|
+
}),
|
|
2979
|
+
retryAttempts,
|
|
2980
|
+
retryDelayMs
|
|
2981
|
+
);
|
|
2982
|
+
results.push(...batchResults);
|
|
2983
|
+
}
|
|
2984
|
+
return results;
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// src/utils/lazy.ts
|
|
2988
|
+
function lazy(pollFn) {
|
|
2989
|
+
return () => async function* () {
|
|
2990
|
+
let active = true;
|
|
2991
|
+
let resolveNext = null;
|
|
2992
|
+
const queue = [];
|
|
2993
|
+
const wait2 = () => new Promise((resolve) => {
|
|
2994
|
+
resolveNext = resolve;
|
|
2995
|
+
});
|
|
2996
|
+
const emit = (item) => {
|
|
2997
|
+
queue.push(item);
|
|
2998
|
+
resolveNext?.();
|
|
2999
|
+
resolveNext = null;
|
|
3000
|
+
};
|
|
3001
|
+
let unpoll = null;
|
|
3002
|
+
const stop = () => {
|
|
3003
|
+
active = false;
|
|
3004
|
+
unpoll?.();
|
|
3005
|
+
resolveNext?.();
|
|
3006
|
+
resolveNext = null;
|
|
3007
|
+
};
|
|
3008
|
+
unpoll = pollFn(emit, { stop });
|
|
3009
|
+
try {
|
|
3010
|
+
while (active) {
|
|
3011
|
+
if (queue.length === 0) await wait2();
|
|
3012
|
+
while (queue.length > 0 && active) yield queue.shift();
|
|
3013
|
+
}
|
|
3014
|
+
} finally {
|
|
3015
|
+
stop();
|
|
3016
|
+
}
|
|
3017
|
+
}();
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
// src/utils/wait.ts
|
|
3021
|
+
async function wait(time) {
|
|
3022
|
+
return new Promise((res) => setTimeout(res, time));
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
// src/utils/poll.ts
|
|
3026
|
+
function poll(fn, { interval }) {
|
|
3027
|
+
let active = true;
|
|
3028
|
+
const unwatch = () => active = false;
|
|
3029
|
+
const watch = async () => {
|
|
3030
|
+
await wait(interval);
|
|
3031
|
+
const poll2 = async () => {
|
|
3032
|
+
if (!active) return;
|
|
3033
|
+
await fn({ unpoll: unwatch });
|
|
3034
|
+
await wait(interval);
|
|
3035
|
+
poll2();
|
|
3036
|
+
};
|
|
3037
|
+
poll2();
|
|
3038
|
+
};
|
|
3039
|
+
watch();
|
|
3040
|
+
return unwatch;
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
// src/utils/time.ts
|
|
3044
|
+
var time_exports = {};
|
|
3045
|
+
__export(time_exports, {
|
|
3046
|
+
max: () => max2,
|
|
3047
|
+
now: () => now
|
|
3048
|
+
});
|
|
3049
|
+
function now() {
|
|
3050
|
+
return Math.floor(Date.now() / 1e3);
|
|
3051
|
+
}
|
|
3052
|
+
function max2() {
|
|
3053
|
+
return 864e16;
|
|
2637
3054
|
}
|
|
2638
3055
|
|
|
2639
|
-
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, Collateral_exports as Collateral, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports as RouterClient, time_exports as Time,
|
|
3056
|
+
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, Collateral_exports as Collateral, Cursor_exports as Cursor, Errors_exports as Errors, Format_exports as Format, GateConfig_exports as GateConfig, Gatekeeper_exports as Gatekeeper, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports as RouterClient, Rules_exports as Rules, time_exports as Time, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation };
|
|
2640
3057
|
//# sourceMappingURL=index.browser.mjs.map
|
|
2641
3058
|
//# sourceMappingURL=index.browser.mjs.map
|