@morpho-dev/router 0.0.17 → 0.0.19
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/dist/index.browser.d.cts +139 -12
- package/dist/index.browser.d.ts +139 -12
- package/dist/index.browser.js +533 -92
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +534 -89
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +132 -750
- package/dist/index.node.d.ts +132 -750
- package/dist/index.node.js +895 -1302
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +894 -1291
- package/dist/index.node.mjs.map +1 -1
- package/package.json +3 -12
- package/dist/drizzle/0000_add-offers-table.sql +0 -37
- package/dist/drizzle/0001_create_offer_status_relation.sql +0 -10
- package/dist/drizzle/0002_add_created_at_in_offer_status_relation.sql +0 -3
- package/dist/drizzle/0003_add-cursor-indices-to-offers.sql +0 -6
- package/dist/drizzle/0004_offer-start.sql +0 -1
- package/dist/drizzle/0005_rename-price-token-buy.sql +0 -8
- package/dist/drizzle/0006_rename-buy.sql +0 -3
- package/dist/drizzle/0007_rename-offering.sql +0 -3
- package/dist/drizzle/0008_add-consumed-relation.sql +0 -10
- package/dist/drizzle/meta/0000_snapshot.json +0 -344
- package/dist/drizzle/meta/0001_snapshot.json +0 -426
- package/dist/drizzle/meta/0002_snapshot.json +0 -439
- package/dist/drizzle/meta/0003_snapshot.json +0 -553
- package/dist/drizzle/meta/0004_snapshot.json +0 -559
- package/dist/drizzle/meta/0005_snapshot.json +0 -559
- package/dist/drizzle/meta/0006_snapshot.json +0 -559
- package/dist/drizzle/meta/0007_snapshot.json +0 -559
- package/dist/drizzle/meta/0008_snapshot.json +0 -635
- package/dist/drizzle/meta/_journal.json +0 -69
package/dist/index.browser.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Errors, Offer, Format } from '@morpho-dev/mempool';
|
|
1
|
+
import { Errors, LLTV, Maturity, Offer, Format, Time } from '@morpho-dev/mempool';
|
|
2
2
|
export * from '@morpho-dev/mempool';
|
|
3
3
|
import { base, mainnet } from 'viem/chains';
|
|
4
|
-
import { maxUint256, parseAbi } from 'viem';
|
|
4
|
+
import { parseUnits, maxUint256, formatUnits, parseAbi } from 'viem';
|
|
5
5
|
import { z } from 'zod/v4';
|
|
6
6
|
import { createDocument } from 'zod-openapi';
|
|
7
7
|
|
|
@@ -67,7 +67,7 @@ var chains = {
|
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
// src/core/Client.ts
|
|
70
|
+
// src/core/router/Client.ts
|
|
71
71
|
var Client_exports = {};
|
|
72
72
|
__export(Client_exports, {
|
|
73
73
|
HttpForbiddenError: () => HttpForbiddenError,
|
|
@@ -138,6 +138,18 @@ var InvalidRouterOfferError = class extends Errors.BaseError {
|
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
140
|
|
|
141
|
+
// src/utils/index.ts
|
|
142
|
+
var utils_exports = {};
|
|
143
|
+
__export(utils_exports, {
|
|
144
|
+
batch: () => batch,
|
|
145
|
+
decodeCursor: () => decodeCursor,
|
|
146
|
+
encodeCursor: () => encodeCursor,
|
|
147
|
+
poll: () => poll,
|
|
148
|
+
retry: () => retry,
|
|
149
|
+
validateCursor: () => validateCursor,
|
|
150
|
+
wait: () => wait
|
|
151
|
+
});
|
|
152
|
+
|
|
141
153
|
// src/utils/batch.ts
|
|
142
154
|
function* batch(array, batchSize) {
|
|
143
155
|
for (let i = 0; i < array.length; i += batchSize) {
|
|
@@ -248,6 +260,20 @@ function poll(fn, { interval }) {
|
|
|
248
260
|
return unwatch;
|
|
249
261
|
}
|
|
250
262
|
|
|
263
|
+
// src/utils/retry.ts
|
|
264
|
+
var retry = async (fn, attempts = 3, delayMs = 50) => {
|
|
265
|
+
let lastErr;
|
|
266
|
+
for (let i = 0; i < attempts; i++) {
|
|
267
|
+
try {
|
|
268
|
+
return await fn();
|
|
269
|
+
} catch (err) {
|
|
270
|
+
lastErr = err;
|
|
271
|
+
if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
throw lastErr;
|
|
275
|
+
};
|
|
276
|
+
|
|
251
277
|
// src/core/apiSchema/requests.ts
|
|
252
278
|
var MAX_LIMIT = 100;
|
|
253
279
|
var DEFAULT_LIMIT = 20;
|
|
@@ -318,19 +344,33 @@ var GetOffersQueryParams = z.object({
|
|
|
318
344
|
example: "1500000000000000000"
|
|
319
345
|
}),
|
|
320
346
|
// Time range
|
|
321
|
-
min_maturity: z.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
347
|
+
min_maturity: z.coerce.number().int().positive().transform((maturity, ctx) => {
|
|
348
|
+
try {
|
|
349
|
+
return Maturity.from(maturity);
|
|
350
|
+
} catch (e) {
|
|
351
|
+
ctx.addIssue({
|
|
352
|
+
code: "custom",
|
|
353
|
+
message: e.message
|
|
354
|
+
});
|
|
355
|
+
return z.NEVER;
|
|
356
|
+
}
|
|
357
|
+
}).optional(),
|
|
358
|
+
max_maturity: z.coerce.number().int().positive().transform((maturity, ctx) => {
|
|
359
|
+
try {
|
|
360
|
+
return Maturity.from(maturity);
|
|
361
|
+
} catch (e) {
|
|
362
|
+
ctx.addIssue({
|
|
363
|
+
code: "custom",
|
|
364
|
+
message: e.message
|
|
365
|
+
});
|
|
366
|
+
return z.NEVER;
|
|
367
|
+
}
|
|
368
|
+
}).optional(),
|
|
369
|
+
min_expiry: z.coerce.number().int().optional().meta({
|
|
330
370
|
description: "Minimum expiry timestamp (Unix timestamp in seconds)",
|
|
331
371
|
example: "1700000000"
|
|
332
372
|
}),
|
|
333
|
-
max_expiry: z.
|
|
373
|
+
max_expiry: z.coerce.number().int().optional().meta({
|
|
334
374
|
description: "Maximum expiry timestamp (Unix timestamp in seconds)",
|
|
335
375
|
example: "1800000000"
|
|
336
376
|
}),
|
|
@@ -352,51 +392,81 @@ var GetOffersQueryParams = z.object({
|
|
|
352
392
|
{
|
|
353
393
|
message: "Collateral tuple must be in format: asset:oracle:lltv#asset2:oracle2:lltv2. Oracle and lltv are optional. Asset must be 0x + 40 hex chars, oracle must be 0x + 40 hex chars, lltv must be a number (e.g., 80.5)."
|
|
354
394
|
}
|
|
355
|
-
).transform((val) => {
|
|
395
|
+
).transform((val, ctx) => {
|
|
356
396
|
return val.split("#").map((tuple) => {
|
|
357
397
|
const parts = tuple.split(":");
|
|
358
398
|
if (parts.length === 0 || !parts[0]) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
]);
|
|
399
|
+
ctx.addIssue({
|
|
400
|
+
code: "custom",
|
|
401
|
+
message: "Asset address is required for each collateral tuple",
|
|
402
|
+
path: ["asset"],
|
|
403
|
+
input: val
|
|
404
|
+
});
|
|
405
|
+
return z.NEVER;
|
|
367
406
|
}
|
|
368
407
|
const asset = parts[0]?.toLowerCase();
|
|
369
408
|
const oracle = parts[1]?.toLowerCase();
|
|
370
409
|
const lltv = parts[2] ? parseFloat(parts[2]) : void 0;
|
|
371
410
|
if (lltv !== void 0 && (lltv < MIN_LLTV || lltv > MAX_LLTV)) {
|
|
372
|
-
|
|
373
|
-
|
|
411
|
+
ctx.addIssue({
|
|
412
|
+
code: "custom",
|
|
413
|
+
message: `LLTV must be between ${MIN_LLTV} and ${MAX_LLTV} (0-100%)`,
|
|
414
|
+
path: ["lltv"],
|
|
415
|
+
input: val
|
|
416
|
+
});
|
|
417
|
+
return z.NEVER;
|
|
418
|
+
}
|
|
419
|
+
let lltvValue;
|
|
420
|
+
if (lltv !== void 0) {
|
|
421
|
+
try {
|
|
422
|
+
lltvValue = LLTV.from(parseUnits(lltv.toString(), 16));
|
|
423
|
+
} catch (e) {
|
|
424
|
+
ctx.issues.push({
|
|
374
425
|
code: "custom",
|
|
375
|
-
message:
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
|
|
426
|
+
message: e instanceof LLTV.InvalidLLTVError || e instanceof LLTV.InvalidOptionError ? e.message : "Invalid LLTV.",
|
|
427
|
+
input: lltv,
|
|
428
|
+
path: ["lltv"]
|
|
429
|
+
});
|
|
430
|
+
return z.NEVER;
|
|
431
|
+
}
|
|
380
432
|
}
|
|
381
433
|
return {
|
|
382
434
|
asset,
|
|
383
435
|
oracle,
|
|
384
|
-
lltv
|
|
436
|
+
lltv: lltvValue
|
|
385
437
|
};
|
|
386
438
|
});
|
|
387
439
|
}).optional().meta({
|
|
388
440
|
description: "Filter by collateral combinations in format: asset:oracle:lltv#asset2:oracle2:lltv2. Oracle and lltv are optional. Use # to separate multiple combinations.",
|
|
389
|
-
example: "0x1234567890123456789012345678901234567890:0xabcdefabcdefabcdefabcdefabcdefabcdefabcd:
|
|
441
|
+
example: "0x1234567890123456789012345678901234567890:0xabcdefabcdefabcdefabcdefabcdefabcdefabcd:86#0x9876543210987654321098765432109876543210:94.5"
|
|
390
442
|
}),
|
|
391
|
-
min_lltv: z.
|
|
392
|
-
|
|
393
|
-
|
|
443
|
+
min_lltv: z.coerce.number().min(0, { message: "LLTV must be above 0" }).max(100, { message: "LLTV must be below 100" }).transform((lltv, ctx) => {
|
|
444
|
+
try {
|
|
445
|
+
return LLTV.from(parseUnits(lltv.toString(), 16));
|
|
446
|
+
} catch (e) {
|
|
447
|
+
ctx.addIssue({
|
|
448
|
+
code: "custom",
|
|
449
|
+
message: e.message,
|
|
450
|
+
input: lltv
|
|
451
|
+
});
|
|
452
|
+
return z.NEVER;
|
|
453
|
+
}
|
|
454
|
+
}).optional().meta({
|
|
394
455
|
description: "Minimum Loan-to-Value ratio (LLTV) for collateral (percentage as decimal, e.g., 80.5 = 80.5%)",
|
|
395
456
|
example: "80.5"
|
|
396
457
|
}),
|
|
397
|
-
max_lltv: z.
|
|
398
|
-
|
|
399
|
-
|
|
458
|
+
max_lltv: z.coerce.number().min(0, { message: "LLTV must be above 0" }).max(100, { message: "LLTV must be below 100" }).transform((lltv, ctx) => {
|
|
459
|
+
try {
|
|
460
|
+
return LLTV.from(parseUnits(lltv.toString(), 16));
|
|
461
|
+
} catch (e) {
|
|
462
|
+
ctx.addIssue({
|
|
463
|
+
code: "custom",
|
|
464
|
+
message: e.message,
|
|
465
|
+
input: lltv
|
|
466
|
+
});
|
|
467
|
+
return z.NEVER;
|
|
468
|
+
}
|
|
469
|
+
}).optional().meta({
|
|
400
470
|
description: "Maximum Loan-to-Value ratio (LLTV) for collateral (percentage as decimal, e.g., 95.5 = 95.5%)",
|
|
401
471
|
example: "95.5"
|
|
402
472
|
}),
|
|
@@ -489,68 +559,89 @@ var MatchOffersQueryParams = z.object({
|
|
|
489
559
|
}),
|
|
490
560
|
// Collateral filtering
|
|
491
561
|
collaterals: z.string().regex(
|
|
492
|
-
/^(0x[a-fA-F0-9]{40}:0x[a-fA-F0-9]{40}
|
|
562
|
+
/^(0x[a-fA-F0-9]{40}:0x[a-fA-F0-9]{40}:[0-9]+(\.[0-9]+)?)(#0x[a-fA-F0-9]{40}:0x[a-fA-F0-9]{40}:[0-9]+(\.[0-9]+)?)*$/,
|
|
493
563
|
{
|
|
494
564
|
message: "Collaterals must be in format: asset:oracle:lltv#asset2:oracle2:lltv2. All fields are required for each collateral."
|
|
495
565
|
}
|
|
496
|
-
).transform((val) => {
|
|
566
|
+
).transform((val, ctx) => {
|
|
497
567
|
return val.split("#").map((collateral) => {
|
|
498
568
|
const parts = collateral.split(":");
|
|
499
569
|
if (parts.length !== 3) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
]);
|
|
570
|
+
ctx.addIssue({
|
|
571
|
+
code: "custom",
|
|
572
|
+
message: "Each collateral must have exactly 3 parts: asset:oracle:lltv",
|
|
573
|
+
path: ["collaterals"],
|
|
574
|
+
input: val
|
|
575
|
+
});
|
|
576
|
+
return z.NEVER;
|
|
508
577
|
}
|
|
509
578
|
const [asset, oracle, lltvStr] = parts;
|
|
510
579
|
if (!asset || !oracle || !lltvStr) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
]);
|
|
580
|
+
ctx.addIssue({
|
|
581
|
+
code: "custom",
|
|
582
|
+
message: "Asset, oracle, and lltv are all required for each collateral",
|
|
583
|
+
path: ["collaterals"],
|
|
584
|
+
input: val
|
|
585
|
+
});
|
|
519
586
|
}
|
|
520
|
-
|
|
521
|
-
if (
|
|
522
|
-
|
|
523
|
-
|
|
587
|
+
let lltvValue;
|
|
588
|
+
if (lltvStr !== void 0) {
|
|
589
|
+
try {
|
|
590
|
+
lltvValue = LLTV.from(parseUnits(lltvStr, 16));
|
|
591
|
+
} catch (e) {
|
|
592
|
+
ctx.issues.push({
|
|
524
593
|
code: "custom",
|
|
525
|
-
message:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
|
|
594
|
+
message: e instanceof LLTV.InvalidLLTVError || e instanceof LLTV.InvalidOptionError ? e.message : "Invalid LLTV.",
|
|
595
|
+
input: lltvStr,
|
|
596
|
+
path: ["lltv"]
|
|
597
|
+
});
|
|
598
|
+
return z.NEVER;
|
|
599
|
+
}
|
|
530
600
|
}
|
|
531
601
|
return {
|
|
532
602
|
asset: asset.toLowerCase(),
|
|
533
603
|
oracle: oracle.toLowerCase(),
|
|
534
|
-
lltv
|
|
604
|
+
lltv: lltvValue
|
|
535
605
|
};
|
|
536
606
|
});
|
|
537
607
|
}).optional().meta({
|
|
538
608
|
description: "Collateral requirements in format: asset:oracle:lltv#asset2:oracle2:lltv2. Use # to separate multiple collaterals.",
|
|
539
|
-
example: "0x1234567890123456789012345678901234567890:0xabcdefabcdefabcdefabcdefabcdefabcdefabcd:
|
|
609
|
+
example: "0x1234567890123456789012345678901234567890:0xabcdefabcdefabcdefabcdefabcdefabcdefabcd:86#0x9876543210987654321098765432109876543210:0xfedcbafedcbafedcbafedcbafedcbafedcbafedc:94.5"
|
|
540
610
|
}),
|
|
541
611
|
// Maturity filtering
|
|
542
|
-
maturity: z.
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
612
|
+
maturity: z.coerce.number().int().positive().transform((maturity, ctx) => {
|
|
613
|
+
try {
|
|
614
|
+
return Maturity.from(maturity);
|
|
615
|
+
} catch (e) {
|
|
616
|
+
ctx.addIssue({
|
|
617
|
+
code: "custom",
|
|
618
|
+
message: e.message
|
|
619
|
+
});
|
|
620
|
+
return z.NEVER;
|
|
621
|
+
}
|
|
622
|
+
}).optional(),
|
|
623
|
+
min_maturity: z.coerce.number().int().positive().transform((maturity, ctx) => {
|
|
624
|
+
try {
|
|
625
|
+
return Maturity.from(maturity);
|
|
626
|
+
} catch (e) {
|
|
627
|
+
ctx.addIssue({
|
|
628
|
+
code: "custom",
|
|
629
|
+
message: e.message
|
|
630
|
+
});
|
|
631
|
+
return z.NEVER;
|
|
632
|
+
}
|
|
633
|
+
}).optional(),
|
|
634
|
+
max_maturity: z.coerce.number().int().positive().transform((maturity, ctx) => {
|
|
635
|
+
try {
|
|
636
|
+
return Maturity.from(maturity);
|
|
637
|
+
} catch (e) {
|
|
638
|
+
ctx.addIssue({
|
|
639
|
+
code: "custom",
|
|
640
|
+
message: e.message
|
|
641
|
+
});
|
|
642
|
+
return z.NEVER;
|
|
643
|
+
}
|
|
644
|
+
}).optional(),
|
|
554
645
|
// Asset and creator filtering
|
|
555
646
|
loan_token: z.string().regex(/^0x[a-fA-F0-9]{40}$/, {
|
|
556
647
|
message: "Loan asset must be a valid Ethereum address"
|
|
@@ -612,8 +703,10 @@ var schemas = {
|
|
|
612
703
|
get_offers: GetOffersQueryParams,
|
|
613
704
|
match_offers: MatchOffersQueryParams
|
|
614
705
|
};
|
|
615
|
-
function safeParse(action, query) {
|
|
616
|
-
return schemas[action].safeParse(query
|
|
706
|
+
function safeParse(action, query, error) {
|
|
707
|
+
return schemas[action].safeParse(query, {
|
|
708
|
+
error
|
|
709
|
+
});
|
|
617
710
|
}
|
|
618
711
|
|
|
619
712
|
// src/core/apiSchema/openapi.ts
|
|
@@ -665,7 +758,7 @@ var paths = {
|
|
|
665
758
|
}
|
|
666
759
|
}
|
|
667
760
|
},
|
|
668
|
-
"/v1/match
|
|
761
|
+
"/v1/offers/match": {
|
|
669
762
|
get: {
|
|
670
763
|
summary: "Match offers",
|
|
671
764
|
description: "Find offers that match specific criteria",
|
|
@@ -739,7 +832,7 @@ function fromResponse(offerResponse) {
|
|
|
739
832
|
};
|
|
740
833
|
}
|
|
741
834
|
|
|
742
|
-
// src/core/Client.ts
|
|
835
|
+
// src/core/router/Client.ts
|
|
743
836
|
function connect(opts) {
|
|
744
837
|
const u = new URL(opts?.url || "https://router.morpho.dev");
|
|
745
838
|
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
@@ -816,16 +909,16 @@ async function get(config, parameters) {
|
|
|
816
909
|
} else if (lltv !== void 0) {
|
|
817
910
|
result += `:`;
|
|
818
911
|
}
|
|
819
|
-
if (lltv !== void 0) result += `:${lltv}`;
|
|
912
|
+
if (lltv !== void 0) result += `:${formatUnits(lltv, 16)}`;
|
|
820
913
|
return result;
|
|
821
914
|
}).join("#");
|
|
822
915
|
url.searchParams.set("collateral_tuple", tupleStr);
|
|
823
916
|
}
|
|
824
917
|
if (parameters.minLltv !== void 0) {
|
|
825
|
-
url.searchParams.set("min_lltv", parameters.minLltv
|
|
918
|
+
url.searchParams.set("min_lltv", formatUnits(parameters.minLltv, 16));
|
|
826
919
|
}
|
|
827
920
|
if (parameters.maxLltv !== void 0) {
|
|
828
|
-
url.searchParams.set("max_lltv", parameters.maxLltv
|
|
921
|
+
url.searchParams.set("max_lltv", formatUnits(parameters.maxLltv, 16));
|
|
829
922
|
}
|
|
830
923
|
if (parameters.sortBy) {
|
|
831
924
|
url.searchParams.set("sort_by", parameters.sortBy);
|
|
@@ -847,14 +940,14 @@ async function get(config, parameters) {
|
|
|
847
940
|
};
|
|
848
941
|
}
|
|
849
942
|
async function match(config, parameters) {
|
|
850
|
-
const url = new URL(`${config.url.toString()}v1/match
|
|
943
|
+
const url = new URL(`${config.url.toString()}v1/offers/match`);
|
|
851
944
|
url.searchParams.set("side", parameters.side);
|
|
852
945
|
url.searchParams.set("chain_id", parameters.chainId.toString());
|
|
853
946
|
if (parameters.rate !== void 0) {
|
|
854
947
|
url.searchParams.set("rate", parameters.rate.toString());
|
|
855
948
|
}
|
|
856
949
|
if (parameters.collaterals?.length) {
|
|
857
|
-
const collateralsStr = parameters.collaterals.map(({ asset, oracle, lltv }) => `${asset}:${oracle}:${lltv}`).join("#");
|
|
950
|
+
const collateralsStr = parameters.collaterals.map(({ asset, oracle, lltv }) => `${asset}:${oracle}:${formatUnits(lltv, 16)}`).join("#");
|
|
858
951
|
url.searchParams.set("collaterals", collateralsStr);
|
|
859
952
|
}
|
|
860
953
|
if (parameters.maturity !== void 0) {
|
|
@@ -895,7 +988,7 @@ async function getApi(config, url) {
|
|
|
895
988
|
case pathname.includes("/v1/offers"):
|
|
896
989
|
action = "get_offers";
|
|
897
990
|
break;
|
|
898
|
-
case pathname.includes("/v1/match
|
|
991
|
+
case pathname.includes("/v1/offers/match"):
|
|
899
992
|
action = "match_offers";
|
|
900
993
|
break;
|
|
901
994
|
default:
|
|
@@ -969,6 +1062,358 @@ var HttpGetOffersFailedError = class extends Errors.BaseError {
|
|
|
969
1062
|
}
|
|
970
1063
|
};
|
|
971
1064
|
|
|
1065
|
+
// src/OfferStore/index.ts
|
|
1066
|
+
var OfferStore_exports = {};
|
|
1067
|
+
__export(OfferStore_exports, {
|
|
1068
|
+
memory: () => memory
|
|
1069
|
+
});
|
|
1070
|
+
function memory(parameters) {
|
|
1071
|
+
const map = parameters.offers;
|
|
1072
|
+
const filled = parameters.filled;
|
|
1073
|
+
const create = async (parameters2) => {
|
|
1074
|
+
if (map.has(parameters2.offer.hash.toLowerCase())) return parameters2.offer.hash;
|
|
1075
|
+
map.set(parameters2.offer.hash.toLowerCase(), {
|
|
1076
|
+
...parameters2.offer,
|
|
1077
|
+
status: parameters2.status,
|
|
1078
|
+
metadata: parameters2.metadata
|
|
1079
|
+
});
|
|
1080
|
+
const chainId = parameters2.offer.chainId;
|
|
1081
|
+
const address = parameters2.offer.offering.toLowerCase();
|
|
1082
|
+
const nonce = parameters2.offer.nonce;
|
|
1083
|
+
const filledForChain = filled.get(chainId) || /* @__PURE__ */ new Map();
|
|
1084
|
+
const filledForOffering = filledForChain.get(address) || /* @__PURE__ */ new Map();
|
|
1085
|
+
if (!filledForOffering.has(nonce)) filledForOffering.set(nonce, 0n);
|
|
1086
|
+
filledForChain.set(address, filledForOffering);
|
|
1087
|
+
filled.set(chainId, filledForChain);
|
|
1088
|
+
return Promise.resolve(parameters2.offer.hash);
|
|
1089
|
+
};
|
|
1090
|
+
const sort = (sortBy, sortOrder, a, b) => {
|
|
1091
|
+
sortBy = sortBy || "expiry";
|
|
1092
|
+
sortOrder = sortOrder || "desc";
|
|
1093
|
+
const sortKey = sortBy === "amount" ? "assets" : sortBy;
|
|
1094
|
+
if (a[sortKey] === b[sortKey]) {
|
|
1095
|
+
if (a.hash === b.hash) return 0;
|
|
1096
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : b.hash > a.hash ? 1 : -1;
|
|
1097
|
+
}
|
|
1098
|
+
switch (sortBy) {
|
|
1099
|
+
case "rate":
|
|
1100
|
+
if (a.rate === b.rate) {
|
|
1101
|
+
if (a.hash === b.hash) return 0;
|
|
1102
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : a.hash > b.hash ? -1 : 1;
|
|
1103
|
+
}
|
|
1104
|
+
return sortOrder === "asc" ? a.rate > b.rate ? 1 : -1 : b.rate > a.rate ? 1 : -1;
|
|
1105
|
+
case "maturity":
|
|
1106
|
+
if (a.maturity === b.maturity) {
|
|
1107
|
+
if (a.hash === b.hash) return 0;
|
|
1108
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : a.hash > b.hash ? -1 : 1;
|
|
1109
|
+
}
|
|
1110
|
+
return sortOrder === "asc" ? a.maturity > b.maturity ? 1 : -1 : b.maturity > a.maturity ? 1 : -1;
|
|
1111
|
+
case "expiry":
|
|
1112
|
+
if (a.expiry === b.expiry) {
|
|
1113
|
+
if (a.hash === b.hash) return 0;
|
|
1114
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : a.hash > b.hash ? -1 : 1;
|
|
1115
|
+
}
|
|
1116
|
+
return sortOrder === "asc" ? a.expiry > b.expiry ? 1 : -1 : b.expiry > a.expiry ? 1 : -1;
|
|
1117
|
+
case "amount":
|
|
1118
|
+
if (a.assets === b.assets) {
|
|
1119
|
+
if (a.hash === b.hash) return 0;
|
|
1120
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : a.hash > b.hash ? -1 : 1;
|
|
1121
|
+
}
|
|
1122
|
+
return sortOrder === "asc" ? a.assets > b.assets ? 1 : -1 : b.assets > a.assets ? 1 : -1;
|
|
1123
|
+
default:
|
|
1124
|
+
if (a.expiry === b.expiry) {
|
|
1125
|
+
if (a.hash === b.hash) return 0;
|
|
1126
|
+
return sortOrder === "asc" ? a.hash > b.hash ? 1 : -1 : a.hash > b.hash ? -1 : 1;
|
|
1127
|
+
}
|
|
1128
|
+
return sortOrder === "asc" ? a.expiry > b.expiry ? 1 : -1 : b.expiry > a.expiry ? 1 : -1;
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
return {
|
|
1132
|
+
create,
|
|
1133
|
+
createMany: async (parameters2) => {
|
|
1134
|
+
return Promise.all(
|
|
1135
|
+
parameters2.map((p) => create({ offer: p.offer, status: p.status, metadata: p.metadata }))
|
|
1136
|
+
);
|
|
1137
|
+
},
|
|
1138
|
+
getAll: async (params) => {
|
|
1139
|
+
const { query } = params || {};
|
|
1140
|
+
let {
|
|
1141
|
+
creators,
|
|
1142
|
+
side,
|
|
1143
|
+
chains: chains2,
|
|
1144
|
+
loanTokens,
|
|
1145
|
+
status = ["valid"],
|
|
1146
|
+
callbackAddresses,
|
|
1147
|
+
minAmount,
|
|
1148
|
+
maxAmount,
|
|
1149
|
+
minRate,
|
|
1150
|
+
maxRate,
|
|
1151
|
+
minMaturity,
|
|
1152
|
+
maxMaturity,
|
|
1153
|
+
minExpiry,
|
|
1154
|
+
maxExpiry,
|
|
1155
|
+
collateralAssets,
|
|
1156
|
+
collateralOracles,
|
|
1157
|
+
collateralTuple,
|
|
1158
|
+
minLltv,
|
|
1159
|
+
maxLltv,
|
|
1160
|
+
sortBy = "expiry",
|
|
1161
|
+
sortOrder = "desc",
|
|
1162
|
+
cursor: queryCursor,
|
|
1163
|
+
limit = 20
|
|
1164
|
+
} = query || {};
|
|
1165
|
+
const now = Time.now();
|
|
1166
|
+
const buy = side === "buy";
|
|
1167
|
+
let offers = Array.from(map.values()).map((o) => ({
|
|
1168
|
+
...o,
|
|
1169
|
+
consumed: filled.get(o.chainId)?.get(o.offering.toLowerCase())?.get(o.nonce) || 0n
|
|
1170
|
+
})).filter((o) => o.consumed < o.assets);
|
|
1171
|
+
const cursor = decodeCursor(queryCursor);
|
|
1172
|
+
if (cursor) {
|
|
1173
|
+
if (cursor.sort !== sortBy || cursor.dir !== sortOrder) {
|
|
1174
|
+
throw new Error("Cursor does not match the current sort parameters");
|
|
1175
|
+
}
|
|
1176
|
+
switch (cursor.sort) {
|
|
1177
|
+
case "rate":
|
|
1178
|
+
offers = offers.filter(
|
|
1179
|
+
(o) => (sortOrder === "asc" ? o.rate >= BigInt(cursor.rate) : o.rate <= BigInt(cursor.rate)) && (o.rate !== BigInt(cursor.rate) || (sortOrder === "asc" ? o.hash > cursor.hash : o.hash < cursor.hash))
|
|
1180
|
+
);
|
|
1181
|
+
break;
|
|
1182
|
+
case "maturity":
|
|
1183
|
+
offers = offers.filter(
|
|
1184
|
+
(o) => (sortOrder === "asc" ? o.maturity >= BigInt(cursor.maturity) : o.maturity <= BigInt(cursor.maturity)) && (o.maturity !== Maturity.from(cursor.maturity) || (sortOrder === "asc" ? o.hash > cursor.hash : o.hash < cursor.hash))
|
|
1185
|
+
);
|
|
1186
|
+
break;
|
|
1187
|
+
case "expiry":
|
|
1188
|
+
offers = offers.filter(
|
|
1189
|
+
(o) => (sortOrder === "asc" ? o.expiry >= cursor.expiry : o.expiry <= cursor.expiry) && (o.expiry !== cursor.expiry || (sortOrder === "asc" ? o.hash > cursor.hash : o.hash < cursor.hash))
|
|
1190
|
+
);
|
|
1191
|
+
break;
|
|
1192
|
+
case "amount":
|
|
1193
|
+
offers = offers.filter(
|
|
1194
|
+
(o) => (sortOrder === "asc" ? o.assets >= BigInt(cursor.assets) : o.assets <= BigInt(cursor.assets)) && (o.assets !== BigInt(cursor.assets) || (sortOrder === "asc" ? o.hash > cursor.hash : o.hash < cursor.hash))
|
|
1195
|
+
);
|
|
1196
|
+
break;
|
|
1197
|
+
default:
|
|
1198
|
+
throw new Error("Invalid sort parameter");
|
|
1199
|
+
}
|
|
1200
|
+
offers = offers.filter((o) => o.hash !== cursor.hash);
|
|
1201
|
+
}
|
|
1202
|
+
creators && (creators = creators.map((c) => c.toLowerCase()));
|
|
1203
|
+
loanTokens && (loanTokens = loanTokens.map((lt) => lt.toLowerCase()));
|
|
1204
|
+
callbackAddresses && (callbackAddresses = callbackAddresses.map((ca) => ca.toLowerCase()));
|
|
1205
|
+
collateralAssets && (collateralAssets = collateralAssets.map((ca) => ca.toLowerCase()));
|
|
1206
|
+
collateralOracles && (collateralOracles = collateralOracles.map((co) => co.toLowerCase()));
|
|
1207
|
+
collateralTuple && (collateralTuple = collateralTuple.map((ct) => ({
|
|
1208
|
+
asset: ct.asset.toLowerCase(),
|
|
1209
|
+
oracle: ct.oracle?.toLowerCase()
|
|
1210
|
+
})));
|
|
1211
|
+
offers = offers.filter((o) => o.expiry >= now);
|
|
1212
|
+
creators && (offers = offers.filter((o) => creators.includes(o.offering.toLowerCase())));
|
|
1213
|
+
side && (offers = offers.filter((o) => o.buy === buy));
|
|
1214
|
+
chains2 && (offers = offers.filter((o) => chains2.includes(Number(o.chainId))));
|
|
1215
|
+
loanTokens && (offers = offers.filter((o) => loanTokens.includes(o.loanToken.toLowerCase())));
|
|
1216
|
+
status && (offers = offers.filter((o) => status.includes(o.status)));
|
|
1217
|
+
callbackAddresses && (offers = offers.filter(
|
|
1218
|
+
(o) => callbackAddresses.includes(o.callback.address.toLowerCase())
|
|
1219
|
+
));
|
|
1220
|
+
minAmount && (offers = offers.filter((o) => o.assets >= minAmount));
|
|
1221
|
+
maxAmount && (offers = offers.filter((o) => o.assets <= maxAmount));
|
|
1222
|
+
minRate && (offers = offers.filter((o) => o.rate >= minRate));
|
|
1223
|
+
maxRate && (offers = offers.filter((o) => o.rate <= maxRate));
|
|
1224
|
+
minMaturity && (offers = offers.filter((o) => o.maturity >= minMaturity));
|
|
1225
|
+
maxMaturity && (offers = offers.filter((o) => o.maturity <= maxMaturity));
|
|
1226
|
+
minExpiry && (offers = offers.filter((o) => o.expiry >= minExpiry));
|
|
1227
|
+
maxExpiry && (offers = offers.filter((o) => o.expiry <= maxExpiry));
|
|
1228
|
+
collateralAssets && (offers = offers.filter(
|
|
1229
|
+
(o) => o.collaterals.some((c) => collateralAssets.includes(c.asset.toLowerCase()))
|
|
1230
|
+
));
|
|
1231
|
+
collateralOracles && (offers = offers.filter(
|
|
1232
|
+
(o) => o.collaterals.some((c) => collateralOracles.includes(c.oracle.toLowerCase()))
|
|
1233
|
+
));
|
|
1234
|
+
collateralTuple && (offers = offers.filter(
|
|
1235
|
+
(o) => o.collaterals.some(
|
|
1236
|
+
(c) => collateralTuple.some(
|
|
1237
|
+
(ct) => c.asset.toLowerCase() === ct.asset.toLowerCase() && (ct.oracle ? c.oracle.toLowerCase() === ct.oracle.toLowerCase() : true) && (ct.lltv ? c.lltv === LLTV.from(BigInt(ct.lltv)) : true)
|
|
1238
|
+
)
|
|
1239
|
+
)
|
|
1240
|
+
));
|
|
1241
|
+
minLltv && (offers = offers.filter((o) => o.collaterals.every((c) => c.lltv >= minLltv)));
|
|
1242
|
+
maxLltv && (offers = offers.filter((o) => o.collaterals.every((c) => c.lltv <= maxLltv)));
|
|
1243
|
+
offers = offers.sort((a, b) => sort(sortBy, sortOrder, a, b));
|
|
1244
|
+
let nextCursor = null;
|
|
1245
|
+
if (offers.length > limit) {
|
|
1246
|
+
const last = offers[limit - 1];
|
|
1247
|
+
const base = {
|
|
1248
|
+
sort: sortBy,
|
|
1249
|
+
dir: sortOrder,
|
|
1250
|
+
hash: last.hash
|
|
1251
|
+
};
|
|
1252
|
+
switch (sortBy) {
|
|
1253
|
+
case "rate":
|
|
1254
|
+
base.rate = last.rate.toString();
|
|
1255
|
+
break;
|
|
1256
|
+
case "amount":
|
|
1257
|
+
base.assets = last.assets.toString();
|
|
1258
|
+
break;
|
|
1259
|
+
case "maturity":
|
|
1260
|
+
base.maturity = last.maturity;
|
|
1261
|
+
break;
|
|
1262
|
+
default:
|
|
1263
|
+
base.expiry = last.expiry;
|
|
1264
|
+
}
|
|
1265
|
+
nextCursor = encodeCursor(base);
|
|
1266
|
+
}
|
|
1267
|
+
offers = offers.slice(0, limit);
|
|
1268
|
+
return {
|
|
1269
|
+
offers,
|
|
1270
|
+
nextCursor
|
|
1271
|
+
};
|
|
1272
|
+
},
|
|
1273
|
+
findMatchingOffers: async (params) => {
|
|
1274
|
+
const {
|
|
1275
|
+
side,
|
|
1276
|
+
chainId,
|
|
1277
|
+
rate,
|
|
1278
|
+
collaterals = [],
|
|
1279
|
+
maturity,
|
|
1280
|
+
minMaturity,
|
|
1281
|
+
maxMaturity,
|
|
1282
|
+
loanToken,
|
|
1283
|
+
creator,
|
|
1284
|
+
status,
|
|
1285
|
+
cursor: queryCursor,
|
|
1286
|
+
limit = 20
|
|
1287
|
+
} = params;
|
|
1288
|
+
const now = Time.now();
|
|
1289
|
+
const isBuying = side === "buy";
|
|
1290
|
+
const sortOrder = isBuying ? "desc" : "asc";
|
|
1291
|
+
let offers = Array.from(map.values()).map((o) => ({
|
|
1292
|
+
...o,
|
|
1293
|
+
consumed: filled.get(o.chainId)?.get(o.offering.toLowerCase())?.get(o.nonce) || 0n
|
|
1294
|
+
})).filter((o) => o.consumed < o.assets);
|
|
1295
|
+
const cursor = decodeCursor(queryCursor);
|
|
1296
|
+
if (cursor) {
|
|
1297
|
+
if (cursor.sort !== "rate" || cursor.dir !== sortOrder) {
|
|
1298
|
+
throw new Error("Cursor does not match the current sort parameters");
|
|
1299
|
+
}
|
|
1300
|
+
offers = offers.filter(
|
|
1301
|
+
(o) => sortOrder === "asc" ? o.rate >= BigInt(cursor.rate) : o.rate <= BigInt(cursor.rate)
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
offers = offers.filter((o) => o.buy === !isBuying);
|
|
1305
|
+
offers = offers.filter((o) => o.chainId === BigInt(chainId));
|
|
1306
|
+
offers = offers.filter((o) => o.expiry >= now);
|
|
1307
|
+
rate && (offers = offers.filter((o) => isBuying ? o.rate >= rate : o.rate <= rate));
|
|
1308
|
+
collaterals.length > 0 && (offers = offers.filter(
|
|
1309
|
+
(o) => isBuying ? (
|
|
1310
|
+
// when wanting to buy, sell offer collaterals ⊆ user buy collaterals
|
|
1311
|
+
o.collaterals.every((oc) => {
|
|
1312
|
+
return collaterals.some(
|
|
1313
|
+
(c) => oc.asset.toLowerCase() === c.asset.toLowerCase() && oc.oracle.toLowerCase() === c.oracle.toLowerCase() && oc.lltv === c.lltv
|
|
1314
|
+
);
|
|
1315
|
+
})
|
|
1316
|
+
) : (
|
|
1317
|
+
// when wanting to sell, user sell collaterals ⊆ buy offer collaterals
|
|
1318
|
+
collaterals.every((c) => {
|
|
1319
|
+
return o.collaterals.some(
|
|
1320
|
+
(oc) => oc.asset.toLowerCase() === c.asset.toLowerCase() && oc.oracle.toLowerCase() === c.oracle.toLowerCase() && oc.lltv === c.lltv
|
|
1321
|
+
);
|
|
1322
|
+
})
|
|
1323
|
+
)
|
|
1324
|
+
));
|
|
1325
|
+
maturity && (offers = offers.filter((o) => o.maturity === maturity));
|
|
1326
|
+
minMaturity && (offers = offers.filter((o) => o.maturity >= minMaturity));
|
|
1327
|
+
maxMaturity && (offers = offers.filter((o) => o.maturity <= maxMaturity));
|
|
1328
|
+
loanToken && (offers = offers.filter((o) => o.loanToken.toLowerCase() === loanToken.toLowerCase()));
|
|
1329
|
+
creator && (offers = offers.filter((o) => o.offering.toLowerCase() === creator.toLowerCase()));
|
|
1330
|
+
status && (offers = offers.filter((o) => status.includes(o.status)));
|
|
1331
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
1332
|
+
for (const offer of offers) {
|
|
1333
|
+
const groupKey = `${offer.chainId}-${offer.offering.toLowerCase()}-${offer.nonce}-${offer.buy}`;
|
|
1334
|
+
const current = byGroup.get(groupKey);
|
|
1335
|
+
if (!current) {
|
|
1336
|
+
byGroup.set(groupKey, offer);
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
const remainingCandidate = offer.assets - offer.consumed;
|
|
1340
|
+
const remainingCurrent = current.assets - current.consumed;
|
|
1341
|
+
let candidateIsBetter = false;
|
|
1342
|
+
if (offer.buy) {
|
|
1343
|
+
if (offer.rate !== current.rate) candidateIsBetter = offer.rate < current.rate;
|
|
1344
|
+
else if (remainingCandidate !== remainingCurrent)
|
|
1345
|
+
candidateIsBetter = remainingCandidate > remainingCurrent;
|
|
1346
|
+
else if (offer.maturity !== current.maturity)
|
|
1347
|
+
candidateIsBetter = offer.maturity > current.maturity;
|
|
1348
|
+
else candidateIsBetter = offer.hash < current.hash;
|
|
1349
|
+
} else {
|
|
1350
|
+
if (offer.rate !== current.rate) candidateIsBetter = offer.rate > current.rate;
|
|
1351
|
+
else if (remainingCandidate !== remainingCurrent)
|
|
1352
|
+
candidateIsBetter = remainingCandidate > remainingCurrent;
|
|
1353
|
+
else if (offer.maturity !== current.maturity)
|
|
1354
|
+
candidateIsBetter = offer.maturity > current.maturity;
|
|
1355
|
+
else candidateIsBetter = offer.hash < current.hash;
|
|
1356
|
+
}
|
|
1357
|
+
if (candidateIsBetter) byGroup.set(groupKey, offer);
|
|
1358
|
+
}
|
|
1359
|
+
offers = Array.from(byGroup.values());
|
|
1360
|
+
offers = offers.sort((a, b) => sort("rate", sortOrder, a, b));
|
|
1361
|
+
cursor && (offers = offers.filter((o) => o.hash !== cursor.hash));
|
|
1362
|
+
let nextCursor = null;
|
|
1363
|
+
if (offers.length > limit) {
|
|
1364
|
+
const last = offers[limit - 1];
|
|
1365
|
+
nextCursor = encodeCursor({
|
|
1366
|
+
sort: "rate",
|
|
1367
|
+
dir: sortOrder,
|
|
1368
|
+
hash: last.hash,
|
|
1369
|
+
rate: last.rate.toString()
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
offers = offers.slice(0, limit);
|
|
1373
|
+
return {
|
|
1374
|
+
offers,
|
|
1375
|
+
nextCursor
|
|
1376
|
+
};
|
|
1377
|
+
},
|
|
1378
|
+
delete: async (hash) => {
|
|
1379
|
+
if (!map.has(hash.toLowerCase())) return false;
|
|
1380
|
+
map.delete(hash.toLowerCase());
|
|
1381
|
+
return true;
|
|
1382
|
+
},
|
|
1383
|
+
deleteMany: async (hashes) => {
|
|
1384
|
+
let deleted = 0;
|
|
1385
|
+
for (const hash of hashes) {
|
|
1386
|
+
if (map.has(hash.toLowerCase())) {
|
|
1387
|
+
map.delete(hash.toLowerCase());
|
|
1388
|
+
deleted++;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
return deleted;
|
|
1392
|
+
},
|
|
1393
|
+
updateStatus: async (parameters2) => {
|
|
1394
|
+
const key = parameters2.offerHash.toLowerCase();
|
|
1395
|
+
const existing = map.get(key);
|
|
1396
|
+
if (!existing) return;
|
|
1397
|
+
if (existing.status === parameters2.status) return;
|
|
1398
|
+
map.set(key, {
|
|
1399
|
+
...existing,
|
|
1400
|
+
status: parameters2.status,
|
|
1401
|
+
metadata: parameters2.metadata
|
|
1402
|
+
});
|
|
1403
|
+
},
|
|
1404
|
+
updateConsumedAmount: async (parameters2) => {
|
|
1405
|
+
const chainId = parameters2.chainId;
|
|
1406
|
+
const address = parameters2.offering.toLowerCase();
|
|
1407
|
+
const nonce = parameters2.nonce;
|
|
1408
|
+
const filledForChain = filled.get(chainId) || /* @__PURE__ */ new Map();
|
|
1409
|
+
const filledForOffering = filledForChain.get(address) || /* @__PURE__ */ new Map();
|
|
1410
|
+
filledForOffering.set(nonce, parameters2.consumed);
|
|
1411
|
+
filledForChain.set(address, filledForOffering);
|
|
1412
|
+
filled.set(chainId, filledForChain);
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
|
|
972
1417
|
// src/RouterEvent.ts
|
|
973
1418
|
var RouterEvent_exports = {};
|
|
974
1419
|
__export(RouterEvent_exports, {
|
|
@@ -1203,6 +1648,6 @@ function morpho(parameters) {
|
|
|
1203
1648
|
];
|
|
1204
1649
|
}
|
|
1205
1650
|
|
|
1206
|
-
export { Chain_exports as Chain, Client_exports as Router, RouterEvent_exports as RouterEvent, RouterOffer_exports as RouterOffer, Validation_exports as Validation, ValidationRule_exports as ValidationRule
|
|
1651
|
+
export { Chain_exports as Chain, OfferStore_exports as OfferStore, Client_exports as Router, RouterEvent_exports as RouterEvent, RouterOffer_exports as RouterOffer, utils_exports as Utils, Validation_exports as Validation, ValidationRule_exports as ValidationRule };
|
|
1207
1652
|
//# sourceMappingURL=index.browser.mjs.map
|
|
1208
1653
|
//# sourceMappingURL=index.browser.mjs.map
|