@morpho-dev/router 0.1.16 → 0.1.17
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/cli.js +623 -369
- package/dist/cli.js.map +1 -1
- package/dist/index.browser.d.cts +158 -77
- package/dist/index.browser.d.ts +158 -77
- package/dist/index.browser.js +353 -214
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +354 -216
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.cts +213 -260
- package/dist/index.node.d.ts +213 -260
- package/dist/index.node.js +5410 -5293
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +5410 -5293
- package/dist/index.node.mjs.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -10,17 +10,17 @@ import { spawn } from 'child_process';
|
|
|
10
10
|
import 'fs';
|
|
11
11
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
12
12
|
import * as z6 from 'zod';
|
|
13
|
-
import { Base64 } from 'js-base64';
|
|
14
13
|
import { readFile } from 'fs/promises';
|
|
15
14
|
import dotenv from 'dotenv';
|
|
16
15
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
17
16
|
import { serve as serve$1 } from '@hono/node-server';
|
|
18
17
|
import { Hono } from 'hono';
|
|
19
18
|
import { cors } from 'hono/cors';
|
|
20
|
-
import { asc, desc, and, eq, gt, gte, sql, lte, inArray } from 'drizzle-orm';
|
|
21
|
-
import { pgSchema, integer, varchar, bigint, timestamp, text, boolean, numeric, index, primaryKey, uniqueIndex } from 'drizzle-orm/pg-core';
|
|
22
19
|
import { z } from 'zod/v4';
|
|
23
20
|
import { createDocument } from 'zod-openapi';
|
|
21
|
+
import { Base64 } from 'js-base64';
|
|
22
|
+
import { asc, desc, and, eq, gt, gte, sql, lte, inArray } from 'drizzle-orm';
|
|
23
|
+
import { pgSchema, integer, varchar, bigint, timestamp, text, boolean, numeric, index, primaryKey, uniqueIndex } from 'drizzle-orm/pg-core';
|
|
24
24
|
import { PGlite } from '@electric-sql/pglite';
|
|
25
25
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
26
26
|
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
@@ -41,7 +41,7 @@ var __export = (target, all) => {
|
|
|
41
41
|
// package.json
|
|
42
42
|
var package_default = {
|
|
43
43
|
name: "@morpho-dev/router",
|
|
44
|
-
version: "0.1.
|
|
44
|
+
version: "0.1.17",
|
|
45
45
|
description: "Router package for Morpho protocol"};
|
|
46
46
|
|
|
47
47
|
// src/core/Chain.ts
|
|
@@ -727,97 +727,6 @@ var from2 = (parameters) => {
|
|
|
727
727
|
};
|
|
728
728
|
};
|
|
729
729
|
|
|
730
|
-
// src/core/Cursor.ts
|
|
731
|
-
var Cursor_exports = {};
|
|
732
|
-
__export(Cursor_exports, {
|
|
733
|
-
decode: () => decode,
|
|
734
|
-
encode: () => encode,
|
|
735
|
-
validate: () => validate
|
|
736
|
-
});
|
|
737
|
-
function validate(cursor) {
|
|
738
|
-
if (!cursor || typeof cursor !== "object") {
|
|
739
|
-
throw new Error("Cursor must be an object");
|
|
740
|
-
}
|
|
741
|
-
const c = cursor;
|
|
742
|
-
if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
|
|
743
|
-
throw new Error(
|
|
744
|
-
`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
|
|
745
|
-
);
|
|
746
|
-
}
|
|
747
|
-
if (!["asc", "desc"].includes(c.dir)) {
|
|
748
|
-
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
749
|
-
}
|
|
750
|
-
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
751
|
-
throw new Error(
|
|
752
|
-
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
const validations = {
|
|
756
|
-
rate: {
|
|
757
|
-
field: "rate",
|
|
758
|
-
type: "string",
|
|
759
|
-
pattern: /^\d+$/,
|
|
760
|
-
error: "numeric string"
|
|
761
|
-
},
|
|
762
|
-
amount: {
|
|
763
|
-
field: "assets",
|
|
764
|
-
type: "string",
|
|
765
|
-
pattern: /^\d+$/,
|
|
766
|
-
error: "numeric string"
|
|
767
|
-
},
|
|
768
|
-
maturity: {
|
|
769
|
-
field: "maturity",
|
|
770
|
-
type: "number",
|
|
771
|
-
validator: (val) => val > 0,
|
|
772
|
-
error: "positive number"
|
|
773
|
-
},
|
|
774
|
-
expiry: {
|
|
775
|
-
field: "expiry",
|
|
776
|
-
type: "number",
|
|
777
|
-
validator: (val) => val > 0,
|
|
778
|
-
error: "positive number"
|
|
779
|
-
}
|
|
780
|
-
};
|
|
781
|
-
const validation = validations[c.sort];
|
|
782
|
-
if (!validation) {
|
|
783
|
-
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
784
|
-
}
|
|
785
|
-
const fieldValue = c[validation.field];
|
|
786
|
-
if (!fieldValue) {
|
|
787
|
-
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
788
|
-
}
|
|
789
|
-
if (typeof fieldValue !== validation.type) {
|
|
790
|
-
throw new Error(
|
|
791
|
-
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
795
|
-
throw new Error(
|
|
796
|
-
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
797
|
-
);
|
|
798
|
-
}
|
|
799
|
-
if (validation.validator && !validation.validator(fieldValue)) {
|
|
800
|
-
throw new Error(
|
|
801
|
-
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
if (c.page !== void 0) {
|
|
805
|
-
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
806
|
-
throw new Error("Invalid page: must be a positive integer");
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
return true;
|
|
810
|
-
}
|
|
811
|
-
function encode(c) {
|
|
812
|
-
return Base64.encodeURL(JSON.stringify(c));
|
|
813
|
-
}
|
|
814
|
-
function decode(token) {
|
|
815
|
-
if (!token) return null;
|
|
816
|
-
const decoded = JSON.parse(Base64.decode(token));
|
|
817
|
-
validate(decoded);
|
|
818
|
-
return decoded;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
730
|
// src/core/Liquidity.ts
|
|
822
731
|
var Liquidity_exports = {};
|
|
823
732
|
__export(Liquidity_exports, {
|
|
@@ -1133,9 +1042,9 @@ __export(Offer_exports, {
|
|
|
1133
1042
|
OfferHashSchema: () => OfferHashSchema,
|
|
1134
1043
|
OfferSchema: () => OfferSchema,
|
|
1135
1044
|
consumedEvent: () => consumedEvent,
|
|
1136
|
-
decode: () =>
|
|
1045
|
+
decode: () => decode,
|
|
1137
1046
|
domain: () => domain,
|
|
1138
|
-
encode: () =>
|
|
1047
|
+
encode: () => encode,
|
|
1139
1048
|
from: () => from5,
|
|
1140
1049
|
fromConsumedLog: () => fromConsumedLog,
|
|
1141
1050
|
fromSnakeCase: () => fromSnakeCase3,
|
|
@@ -1460,7 +1369,7 @@ var OfferAbi = [
|
|
|
1460
1369
|
},
|
|
1461
1370
|
{ name: "signature", type: "bytes" }
|
|
1462
1371
|
];
|
|
1463
|
-
function
|
|
1372
|
+
function encode(offer) {
|
|
1464
1373
|
return encodeAbiParameters(OfferAbi, [
|
|
1465
1374
|
offer.offering,
|
|
1466
1375
|
offer.assets,
|
|
@@ -1477,7 +1386,7 @@ function encode2(offer) {
|
|
|
1477
1386
|
offer.signature ?? "0x"
|
|
1478
1387
|
]);
|
|
1479
1388
|
}
|
|
1480
|
-
function
|
|
1389
|
+
function decode(data, blockNumber) {
|
|
1481
1390
|
let decoded;
|
|
1482
1391
|
try {
|
|
1483
1392
|
decoded = decodeAbiParameters(OfferAbi, data);
|
|
@@ -1547,6 +1456,57 @@ var AccountNotSetError = class extends BaseError {
|
|
|
1547
1456
|
}
|
|
1548
1457
|
};
|
|
1549
1458
|
|
|
1459
|
+
// src/core/Quote.ts
|
|
1460
|
+
var Quote_exports = {};
|
|
1461
|
+
__export(Quote_exports, {
|
|
1462
|
+
InvalidQuoteError: () => InvalidQuoteError,
|
|
1463
|
+
QuoteSchema: () => QuoteSchema,
|
|
1464
|
+
from: () => from6,
|
|
1465
|
+
fromSnakeCase: () => fromSnakeCase4,
|
|
1466
|
+
random: () => random3
|
|
1467
|
+
});
|
|
1468
|
+
var QuoteSchema = z6.object({
|
|
1469
|
+
obligationId: z6.string().transform(transformHex),
|
|
1470
|
+
ask: z6.object({
|
|
1471
|
+
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1472
|
+
}),
|
|
1473
|
+
bid: z6.object({
|
|
1474
|
+
rate: z6.bigint({ coerce: true }).min(0n).max(maxUint256)
|
|
1475
|
+
})
|
|
1476
|
+
});
|
|
1477
|
+
function from6(parameters) {
|
|
1478
|
+
try {
|
|
1479
|
+
const parsedQuote = QuoteSchema.parse(parameters);
|
|
1480
|
+
return {
|
|
1481
|
+
obligationId: parsedQuote.obligationId,
|
|
1482
|
+
ask: parsedQuote.ask,
|
|
1483
|
+
bid: parsedQuote.bid
|
|
1484
|
+
};
|
|
1485
|
+
} catch (error2) {
|
|
1486
|
+
throw new InvalidQuoteError(error2);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
function fromSnakeCase4(snake) {
|
|
1490
|
+
return from6(fromSnakeCase(snake));
|
|
1491
|
+
}
|
|
1492
|
+
function random3() {
|
|
1493
|
+
return from6({
|
|
1494
|
+
obligationId: Obligation_exports.id(Obligation_exports.random()),
|
|
1495
|
+
ask: {
|
|
1496
|
+
rate: BigInt(Math.floor(Math.random() * 1e6))
|
|
1497
|
+
},
|
|
1498
|
+
bid: {
|
|
1499
|
+
rate: BigInt(Math.floor(Math.random() * 1e6))
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
var InvalidQuoteError = class extends BaseError {
|
|
1504
|
+
name = "Quote.InvalidQuoteError";
|
|
1505
|
+
constructor(error2) {
|
|
1506
|
+
super("Invalid quote.", { cause: error2 });
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1550
1510
|
// src/evm/EVM.ts
|
|
1551
1511
|
var users = [
|
|
1552
1512
|
privateKeyToAccount(
|
|
@@ -1663,11 +1623,16 @@ function defaultLogger(minLevel, pretty) {
|
|
|
1663
1623
|
return;
|
|
1664
1624
|
}
|
|
1665
1625
|
const { msg, ...rest } = entry;
|
|
1626
|
+
const stack = typeof rest.stack === "string" ? rest.stack : void 0;
|
|
1627
|
+
if (stack) delete rest.stack;
|
|
1666
1628
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
1667
1629
|
const level = methodLevel.toUpperCase();
|
|
1668
1630
|
const extras = Object.entries(rest).map(([k, v]) => `${k}=${formatValue(v)}`).join(" ");
|
|
1669
1631
|
const line = extras.length > 0 ? `${timestamp2} [${level}] ${msg} ${extras}` : `${timestamp2} [${level}] ${msg}`;
|
|
1670
1632
|
console[consoleMethod](line);
|
|
1633
|
+
if (stack) {
|
|
1634
|
+
console[consoleMethod](stack);
|
|
1635
|
+
}
|
|
1671
1636
|
} : () => {
|
|
1672
1637
|
};
|
|
1673
1638
|
return {
|
|
@@ -1709,6 +1674,442 @@ function formatValue(value) {
|
|
|
1709
1674
|
}
|
|
1710
1675
|
}
|
|
1711
1676
|
}
|
|
1677
|
+
var CollectorHealth = z.object({
|
|
1678
|
+
name: z.string(),
|
|
1679
|
+
chain_id: z.number(),
|
|
1680
|
+
block_number: z.number().nullable(),
|
|
1681
|
+
updated_at: z.string().nullable(),
|
|
1682
|
+
lag: z.number().nullable(),
|
|
1683
|
+
status: z.enum(["live", "lagging", "unknown"])
|
|
1684
|
+
});
|
|
1685
|
+
var CollectorsHealthResponse = z.array(CollectorHealth);
|
|
1686
|
+
var ChainHealth = z.object({
|
|
1687
|
+
chain_id: z.number(),
|
|
1688
|
+
block_number: z.number(),
|
|
1689
|
+
updated_at: z.string()
|
|
1690
|
+
});
|
|
1691
|
+
var ChainsHealthResponse = z.array(ChainHealth);
|
|
1692
|
+
var RouterStatusResponse = z.object({
|
|
1693
|
+
status: z.enum(["live", "syncing"])
|
|
1694
|
+
});
|
|
1695
|
+
|
|
1696
|
+
// src/stores/utils/Cursor.ts
|
|
1697
|
+
var Cursor_exports = {};
|
|
1698
|
+
__export(Cursor_exports, {
|
|
1699
|
+
decode: () => decode2,
|
|
1700
|
+
encode: () => encode2,
|
|
1701
|
+
validate: () => validate
|
|
1702
|
+
});
|
|
1703
|
+
function validate(cursor) {
|
|
1704
|
+
if (!cursor || typeof cursor !== "object") {
|
|
1705
|
+
throw new Error("Cursor must be an object");
|
|
1706
|
+
}
|
|
1707
|
+
const c = cursor;
|
|
1708
|
+
if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
|
|
1709
|
+
throw new Error(
|
|
1710
|
+
`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
if (!["asc", "desc"].includes(c.dir)) {
|
|
1714
|
+
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
1715
|
+
}
|
|
1716
|
+
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
1717
|
+
throw new Error(
|
|
1718
|
+
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
const validations = {
|
|
1722
|
+
rate: {
|
|
1723
|
+
field: "rate",
|
|
1724
|
+
type: "string",
|
|
1725
|
+
pattern: /^\d+$/,
|
|
1726
|
+
error: "numeric string"
|
|
1727
|
+
},
|
|
1728
|
+
amount: {
|
|
1729
|
+
field: "assets",
|
|
1730
|
+
type: "string",
|
|
1731
|
+
pattern: /^\d+$/,
|
|
1732
|
+
error: "numeric string"
|
|
1733
|
+
},
|
|
1734
|
+
maturity: {
|
|
1735
|
+
field: "maturity",
|
|
1736
|
+
type: "number",
|
|
1737
|
+
validator: (val) => val > 0,
|
|
1738
|
+
error: "positive number"
|
|
1739
|
+
},
|
|
1740
|
+
expiry: {
|
|
1741
|
+
field: "expiry",
|
|
1742
|
+
type: "number",
|
|
1743
|
+
validator: (val) => val > 0,
|
|
1744
|
+
error: "positive number"
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
const validation = validations[c.sort];
|
|
1748
|
+
if (!validation) {
|
|
1749
|
+
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
1750
|
+
}
|
|
1751
|
+
const fieldValue = c[validation.field];
|
|
1752
|
+
if (!fieldValue) {
|
|
1753
|
+
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
1754
|
+
}
|
|
1755
|
+
if (typeof fieldValue !== validation.type) {
|
|
1756
|
+
throw new Error(
|
|
1757
|
+
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
1761
|
+
throw new Error(
|
|
1762
|
+
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
if (validation.validator && !validation.validator(fieldValue)) {
|
|
1766
|
+
throw new Error(
|
|
1767
|
+
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
1768
|
+
);
|
|
1769
|
+
}
|
|
1770
|
+
if (c.page !== void 0) {
|
|
1771
|
+
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
1772
|
+
throw new Error("Invalid page: must be a positive integer");
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
return true;
|
|
1776
|
+
}
|
|
1777
|
+
function encode2(c) {
|
|
1778
|
+
return Base64.encodeURL(JSON.stringify(c));
|
|
1779
|
+
}
|
|
1780
|
+
function decode2(token) {
|
|
1781
|
+
if (!token) return null;
|
|
1782
|
+
const decoded = JSON.parse(Base64.decode(token));
|
|
1783
|
+
validate(decoded);
|
|
1784
|
+
return decoded;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// src/api/Schema/requests.ts
|
|
1788
|
+
var MAX_LIMIT = 100;
|
|
1789
|
+
var DEFAULT_LIMIT = 20;
|
|
1790
|
+
var PaginationQueryParams = z6.object({
|
|
1791
|
+
cursor: z6.string().optional().refine(
|
|
1792
|
+
(val) => {
|
|
1793
|
+
if (!val) return true;
|
|
1794
|
+
try {
|
|
1795
|
+
const decoded = Cursor_exports.decode(val);
|
|
1796
|
+
return decoded !== null;
|
|
1797
|
+
} catch (_error) {
|
|
1798
|
+
return false;
|
|
1799
|
+
}
|
|
1800
|
+
},
|
|
1801
|
+
{
|
|
1802
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1803
|
+
}
|
|
1804
|
+
).meta({
|
|
1805
|
+
description: "Pagination cursor in base64url-encoded format",
|
|
1806
|
+
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
1807
|
+
}),
|
|
1808
|
+
limit: z6.string().regex(/^[1-9]\d*$/, {
|
|
1809
|
+
message: "Limit must be a positive integer"
|
|
1810
|
+
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
1811
|
+
z6.number().max(MAX_LIMIT, {
|
|
1812
|
+
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
1813
|
+
})
|
|
1814
|
+
).optional().default(DEFAULT_LIMIT).meta({
|
|
1815
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
1816
|
+
example: 10
|
|
1817
|
+
})
|
|
1818
|
+
});
|
|
1819
|
+
var GetOffersQueryParams = z6.object({
|
|
1820
|
+
...PaginationQueryParams.shape,
|
|
1821
|
+
side: z6.enum(["buy", "sell"]).meta({
|
|
1822
|
+
description: "Side of the offer.",
|
|
1823
|
+
example: "buy"
|
|
1824
|
+
}),
|
|
1825
|
+
obligation_id: z6.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({
|
|
1826
|
+
description: "Offers obligation id",
|
|
1827
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1828
|
+
})
|
|
1829
|
+
});
|
|
1830
|
+
var GetObligationsQueryParams = z6.object({
|
|
1831
|
+
...PaginationQueryParams.shape,
|
|
1832
|
+
cursor: z6.string().optional().meta({
|
|
1833
|
+
description: "Obligation id cursor",
|
|
1834
|
+
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
1835
|
+
})
|
|
1836
|
+
});
|
|
1837
|
+
var schemas = {
|
|
1838
|
+
get_offers: GetOffersQueryParams,
|
|
1839
|
+
get_obligations: GetObligationsQueryParams
|
|
1840
|
+
};
|
|
1841
|
+
function safeParse(action, query, error2) {
|
|
1842
|
+
return schemas[action].safeParse(query, {
|
|
1843
|
+
error: error2
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// src/api/Schema/openapi.ts
|
|
1848
|
+
var timestampExample = "2024-01-01T12:00:00.000Z";
|
|
1849
|
+
var cursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
1850
|
+
function makeSuccessResponse(parameters) {
|
|
1851
|
+
const { dataSchema, dataDescription, dataExample, cursor } = parameters;
|
|
1852
|
+
const withDataMeta = dataDescription ? dataSchema.meta({ description: dataDescription }) : dataSchema;
|
|
1853
|
+
return z.object({
|
|
1854
|
+
status: z.literal("success"),
|
|
1855
|
+
cursor: z.string().nullable(),
|
|
1856
|
+
data: z.any(),
|
|
1857
|
+
meta: z.object({
|
|
1858
|
+
timestamp: z.string()
|
|
1859
|
+
})
|
|
1860
|
+
}).extend({
|
|
1861
|
+
data: withDataMeta
|
|
1862
|
+
}).meta({
|
|
1863
|
+
example: {
|
|
1864
|
+
status: "success",
|
|
1865
|
+
cursor,
|
|
1866
|
+
data: dataExample,
|
|
1867
|
+
meta: { timestamp: timestampExample }
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
var OffersSuccessResponseSchema = makeSuccessResponse({
|
|
1872
|
+
dataSchema: z.array(z.any()),
|
|
1873
|
+
dataDescription: "Offers matching the provided filters.",
|
|
1874
|
+
dataExample: [toSnakeCase(Offer_exports.random())],
|
|
1875
|
+
cursor: cursorExample
|
|
1876
|
+
});
|
|
1877
|
+
var ObligationsSuccessResponseSchema = makeSuccessResponse({
|
|
1878
|
+
dataSchema: z.array(z.any()),
|
|
1879
|
+
dataDescription: "Obligations known to the router.",
|
|
1880
|
+
dataExample: [toSnakeCase(Obligation_exports.random())],
|
|
1881
|
+
cursor: cursorExample
|
|
1882
|
+
});
|
|
1883
|
+
var RouterStatusSuccessResponseSchema = makeSuccessResponse({
|
|
1884
|
+
dataSchema: RouterStatusResponse,
|
|
1885
|
+
dataDescription: "Aggregated router status.",
|
|
1886
|
+
dataExample: { status: "live" },
|
|
1887
|
+
cursor: null
|
|
1888
|
+
});
|
|
1889
|
+
var CollectorsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1890
|
+
dataSchema: CollectorsHealthResponse,
|
|
1891
|
+
dataDescription: "Collectors health details and sync status.",
|
|
1892
|
+
dataExample: [
|
|
1893
|
+
{
|
|
1894
|
+
name: "mempool_offers",
|
|
1895
|
+
chain_id: "1",
|
|
1896
|
+
block_number: 21345678,
|
|
1897
|
+
updated_at: "2024-01-01T12:00:00.000Z",
|
|
1898
|
+
lag: 0,
|
|
1899
|
+
status: "live"
|
|
1900
|
+
}
|
|
1901
|
+
],
|
|
1902
|
+
cursor: null
|
|
1903
|
+
});
|
|
1904
|
+
var ChainsHealthSuccessResponseSchema = makeSuccessResponse({
|
|
1905
|
+
dataSchema: ChainsHealthResponse,
|
|
1906
|
+
dataDescription: "Latest processed block per chain.",
|
|
1907
|
+
dataExample: [
|
|
1908
|
+
{
|
|
1909
|
+
chain_id: "1",
|
|
1910
|
+
block_number: 21345678,
|
|
1911
|
+
updated_at: "2024-01-01T12:00:00.000Z"
|
|
1912
|
+
}
|
|
1913
|
+
],
|
|
1914
|
+
cursor: null
|
|
1915
|
+
});
|
|
1916
|
+
var errorResponseSchema = z.object({
|
|
1917
|
+
status: z.literal("error"),
|
|
1918
|
+
error: z.object({
|
|
1919
|
+
code: z.string(),
|
|
1920
|
+
message: z.string(),
|
|
1921
|
+
details: z.any().optional()
|
|
1922
|
+
}),
|
|
1923
|
+
meta: z.object({
|
|
1924
|
+
timestamp: z.string()
|
|
1925
|
+
})
|
|
1926
|
+
}).meta({
|
|
1927
|
+
description: "Error response wrapper.",
|
|
1928
|
+
example: {
|
|
1929
|
+
status: "error",
|
|
1930
|
+
error: {
|
|
1931
|
+
code: "VALIDATION_ERROR",
|
|
1932
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object",
|
|
1933
|
+
details: [
|
|
1934
|
+
{
|
|
1935
|
+
field: "cursor",
|
|
1936
|
+
issue: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
1937
|
+
}
|
|
1938
|
+
]
|
|
1939
|
+
},
|
|
1940
|
+
meta: {
|
|
1941
|
+
timestamp: timestampExample
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
});
|
|
1945
|
+
var paths = {
|
|
1946
|
+
"/v1/offers": {
|
|
1947
|
+
get: {
|
|
1948
|
+
summary: "Offers",
|
|
1949
|
+
description: "Find offers that match specific criteria",
|
|
1950
|
+
tags: ["Offers"],
|
|
1951
|
+
requestParams: {
|
|
1952
|
+
query: GetOffersQueryParams
|
|
1953
|
+
},
|
|
1954
|
+
responses: {
|
|
1955
|
+
200: {
|
|
1956
|
+
description: "Success",
|
|
1957
|
+
content: {
|
|
1958
|
+
"application/json": {
|
|
1959
|
+
schema: OffersSuccessResponseSchema
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
},
|
|
1963
|
+
400: {
|
|
1964
|
+
description: "Bad Request",
|
|
1965
|
+
content: {
|
|
1966
|
+
"application/json": {
|
|
1967
|
+
schema: errorResponseSchema
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
},
|
|
1974
|
+
"/v1/obligations": {
|
|
1975
|
+
get: {
|
|
1976
|
+
summary: "Obligations",
|
|
1977
|
+
description: "List obligations with pagination support",
|
|
1978
|
+
tags: ["Obligations"],
|
|
1979
|
+
requestParams: {
|
|
1980
|
+
query: GetObligationsQueryParams
|
|
1981
|
+
},
|
|
1982
|
+
responses: {
|
|
1983
|
+
200: {
|
|
1984
|
+
description: "Success",
|
|
1985
|
+
content: {
|
|
1986
|
+
"application/json": {
|
|
1987
|
+
schema: ObligationsSuccessResponseSchema
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
},
|
|
1991
|
+
400: {
|
|
1992
|
+
description: "Bad Request",
|
|
1993
|
+
content: {
|
|
1994
|
+
"application/json": {
|
|
1995
|
+
schema: errorResponseSchema
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
},
|
|
2002
|
+
"/v1/health": {
|
|
2003
|
+
get: {
|
|
2004
|
+
summary: "Router status",
|
|
2005
|
+
description: "Retrieve the aggregated status of the router.",
|
|
2006
|
+
tags: ["Health"],
|
|
2007
|
+
responses: {
|
|
2008
|
+
200: {
|
|
2009
|
+
description: "Success",
|
|
2010
|
+
content: {
|
|
2011
|
+
"application/json": {
|
|
2012
|
+
schema: RouterStatusSuccessResponseSchema
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
},
|
|
2019
|
+
"/v1/health/collectors": {
|
|
2020
|
+
get: {
|
|
2021
|
+
summary: "Collectors health",
|
|
2022
|
+
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
2023
|
+
tags: ["Health"],
|
|
2024
|
+
responses: {
|
|
2025
|
+
200: {
|
|
2026
|
+
description: "Success",
|
|
2027
|
+
content: {
|
|
2028
|
+
"application/json": {
|
|
2029
|
+
schema: CollectorsHealthSuccessResponseSchema
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
"/v1/health/chains": {
|
|
2037
|
+
get: {
|
|
2038
|
+
summary: "Chains health",
|
|
2039
|
+
description: "Retrieve the latest block processed for each chain.",
|
|
2040
|
+
tags: ["Health"],
|
|
2041
|
+
responses: {
|
|
2042
|
+
200: {
|
|
2043
|
+
description: "Success",
|
|
2044
|
+
content: {
|
|
2045
|
+
"application/json": {
|
|
2046
|
+
schema: ChainsHealthSuccessResponseSchema
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
var OpenApi = createDocument({
|
|
2055
|
+
openapi: "3.1.0",
|
|
2056
|
+
info: {
|
|
2057
|
+
title: "Router API",
|
|
2058
|
+
version: "1.0.0",
|
|
2059
|
+
description: "API for the Morpho Router"
|
|
2060
|
+
},
|
|
2061
|
+
tags: [
|
|
2062
|
+
{
|
|
2063
|
+
name: "Offers"
|
|
2064
|
+
},
|
|
2065
|
+
{
|
|
2066
|
+
name: "Obligations"
|
|
2067
|
+
},
|
|
2068
|
+
{
|
|
2069
|
+
name: "Health"
|
|
2070
|
+
}
|
|
2071
|
+
],
|
|
2072
|
+
servers: [
|
|
2073
|
+
{
|
|
2074
|
+
url: "https://router.morpho.dev",
|
|
2075
|
+
description: "Production server"
|
|
2076
|
+
},
|
|
2077
|
+
{
|
|
2078
|
+
url: "http://localhost:7891",
|
|
2079
|
+
description: "Local development server"
|
|
2080
|
+
}
|
|
2081
|
+
],
|
|
2082
|
+
paths
|
|
2083
|
+
});
|
|
2084
|
+
|
|
2085
|
+
// src/api/Controllers/getDocs.ts
|
|
2086
|
+
function getSwaggerJson() {
|
|
2087
|
+
return OpenApi;
|
|
2088
|
+
}
|
|
2089
|
+
function getDocsHtml() {
|
|
2090
|
+
const html = `<!DOCTYPE html>
|
|
2091
|
+
<html>
|
|
2092
|
+
<head>
|
|
2093
|
+
<meta charset="UTF-8">
|
|
2094
|
+
<title>Router API Docs (Scalar)</title>
|
|
2095
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
2096
|
+
<style>
|
|
2097
|
+
html, body { margin: 0; height: 100%; }
|
|
2098
|
+
api-reference { height: 100%; width: 100%; }
|
|
2099
|
+
</style>
|
|
2100
|
+
</head>
|
|
2101
|
+
<body>
|
|
2102
|
+
<div id="api-container" style="height:100%;width:100%;"></div>
|
|
2103
|
+
<script>
|
|
2104
|
+
window.addEventListener('load', function () {
|
|
2105
|
+
const spec = ${JSON.stringify(OpenApi)};
|
|
2106
|
+
Scalar.createApiReference('#api-container', { spec: { content: spec } });
|
|
2107
|
+
});
|
|
2108
|
+
</script>
|
|
2109
|
+
</body>
|
|
2110
|
+
</html>`;
|
|
2111
|
+
return html;
|
|
2112
|
+
}
|
|
1712
2113
|
|
|
1713
2114
|
// src/collectors/index.ts
|
|
1714
2115
|
var collectors_exports = {};
|
|
@@ -1991,20 +2392,31 @@ function create2({
|
|
|
1991
2392
|
});
|
|
1992
2393
|
return poll(
|
|
1993
2394
|
async () => {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2395
|
+
try {
|
|
2396
|
+
let { blockNumber: lastBlockNumber, epoch } = await collectorStore.getBlockNumber({
|
|
2397
|
+
collectorName: name,
|
|
2398
|
+
chainId: chain.id
|
|
2399
|
+
});
|
|
2400
|
+
await admin.syncBlock();
|
|
2401
|
+
lastBlockNumber = await collect({
|
|
2402
|
+
chain,
|
|
2403
|
+
client,
|
|
2404
|
+
collector: name,
|
|
2405
|
+
epoch,
|
|
2406
|
+
lastBlockNumber,
|
|
2407
|
+
withTransaction
|
|
2408
|
+
});
|
|
2409
|
+
emit(lastBlockNumber);
|
|
2410
|
+
} catch (err) {
|
|
2411
|
+
const isError = err instanceof Error;
|
|
2412
|
+
logger.error({
|
|
2413
|
+
msg: "Collector error",
|
|
2414
|
+
collector,
|
|
2415
|
+
chain_id: chain.id,
|
|
2416
|
+
error: isError ? err.message : String(err),
|
|
2417
|
+
stack: isError ? err.stack : void 0
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2008
2420
|
},
|
|
2009
2421
|
{ interval: options.interval }
|
|
2010
2422
|
);
|
|
@@ -2024,7 +2436,7 @@ function start(collector) {
|
|
|
2024
2436
|
}
|
|
2025
2437
|
var DEFAULT_BATCH_SIZE2 = 100;
|
|
2026
2438
|
var DEFAULT_BLOCK_WINDOW2 = 100;
|
|
2027
|
-
function
|
|
2439
|
+
function from7(parameters) {
|
|
2028
2440
|
const config = {
|
|
2029
2441
|
client: parameters.client,
|
|
2030
2442
|
mempoolAddress: parameters.mempoolAddress,
|
|
@@ -2166,7 +2578,7 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
2166
2578
|
|
|
2167
2579
|
// src/mempool/MempoolClient.ts
|
|
2168
2580
|
function connect(parameters) {
|
|
2169
|
-
return
|
|
2581
|
+
return from7(parameters);
|
|
2170
2582
|
}
|
|
2171
2583
|
|
|
2172
2584
|
// src/stores/CollectorStore.ts
|
|
@@ -4006,7 +4418,7 @@ function handleZodError(error2) {
|
|
|
4006
4418
|
return new ValidationError("Validation failed", formattedErrors);
|
|
4007
4419
|
}
|
|
4008
4420
|
|
|
4009
|
-
// src/api/
|
|
4421
|
+
// src/api/Controllers/getHealth.ts
|
|
4010
4422
|
async function getHealth(healthService) {
|
|
4011
4423
|
const logger = Logger_exports.getLogger();
|
|
4012
4424
|
try {
|
|
@@ -4071,266 +4483,31 @@ async function getHealthCollectors(healthService) {
|
|
|
4071
4483
|
return error(err);
|
|
4072
4484
|
}
|
|
4073
4485
|
}
|
|
4074
|
-
var CollectorHealth = z.object({
|
|
4075
|
-
name: z.string(),
|
|
4076
|
-
chain_id: z.number(),
|
|
4077
|
-
block_number: z.number().nullable(),
|
|
4078
|
-
updated_at: z.string().nullable(),
|
|
4079
|
-
lag: z.number().nullable(),
|
|
4080
|
-
status: z.enum(["live", "lagging", "unknown"])
|
|
4081
|
-
});
|
|
4082
|
-
var CollectorsHealthResponse = z.object({
|
|
4083
|
-
collectors: z.array(CollectorHealth)
|
|
4084
|
-
});
|
|
4085
|
-
var ChainHealth = z.object({
|
|
4086
|
-
chain_id: z.number(),
|
|
4087
|
-
block_number: z.number(),
|
|
4088
|
-
updated_at: z.string()
|
|
4089
|
-
});
|
|
4090
|
-
var ChainsHealthResponse = z.object({
|
|
4091
|
-
chains: z.array(ChainHealth)
|
|
4092
|
-
});
|
|
4093
|
-
var RouterStatusResponse = z.object({
|
|
4094
|
-
status: z.enum(["live", "syncing"])
|
|
4095
|
-
});
|
|
4096
4486
|
|
|
4097
|
-
// src/api/
|
|
4487
|
+
// src/api/Schema/ObligationResponse.ts
|
|
4098
4488
|
var ObligationResponse_exports = {};
|
|
4099
4489
|
__export(ObligationResponse_exports, {
|
|
4100
|
-
from: () =>
|
|
4490
|
+
from: () => from8
|
|
4101
4491
|
});
|
|
4102
|
-
function
|
|
4103
|
-
return toSnakeCase({
|
|
4492
|
+
function from8(obligation, quote) {
|
|
4493
|
+
return toSnakeCase({
|
|
4494
|
+
id: quote.obligationId,
|
|
4495
|
+
...obligation,
|
|
4496
|
+
ask: quote.ask,
|
|
4497
|
+
bid: quote.bid
|
|
4498
|
+
});
|
|
4104
4499
|
}
|
|
4105
4500
|
|
|
4106
|
-
// src/api/
|
|
4501
|
+
// src/api/Schema/OfferResponse.ts
|
|
4107
4502
|
var OfferResponse_exports = {};
|
|
4108
4503
|
__export(OfferResponse_exports, {
|
|
4109
|
-
from: () =>
|
|
4504
|
+
from: () => from9
|
|
4110
4505
|
});
|
|
4111
|
-
function
|
|
4506
|
+
function from9(offer) {
|
|
4112
4507
|
return toSnakeCase(offer);
|
|
4113
4508
|
}
|
|
4114
|
-
var MAX_LIMIT = 100;
|
|
4115
|
-
var DEFAULT_LIMIT = 20;
|
|
4116
|
-
var PaginationQueryParams = z6.object({
|
|
4117
|
-
cursor: z6.string().optional().refine(
|
|
4118
|
-
(val) => {
|
|
4119
|
-
if (!val) return true;
|
|
4120
|
-
try {
|
|
4121
|
-
const decoded = Cursor_exports.decode(val);
|
|
4122
|
-
return decoded !== null;
|
|
4123
|
-
} catch (_error) {
|
|
4124
|
-
return false;
|
|
4125
|
-
}
|
|
4126
|
-
},
|
|
4127
|
-
{
|
|
4128
|
-
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
4129
|
-
}
|
|
4130
|
-
).meta({
|
|
4131
|
-
description: "Pagination cursor in base64url-encoded format",
|
|
4132
|
-
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
4133
|
-
}),
|
|
4134
|
-
limit: z6.string().regex(/^[1-9]\d*$/, {
|
|
4135
|
-
message: "Limit must be a positive integer"
|
|
4136
|
-
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
4137
|
-
z6.number().max(MAX_LIMIT, {
|
|
4138
|
-
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
4139
|
-
})
|
|
4140
|
-
).optional().default(DEFAULT_LIMIT).meta({
|
|
4141
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
4142
|
-
example: 10
|
|
4143
|
-
})
|
|
4144
|
-
});
|
|
4145
|
-
var GetOffersQueryParams = z6.object({
|
|
4146
|
-
...PaginationQueryParams.shape,
|
|
4147
|
-
side: z6.enum(["buy", "sell"]).meta({
|
|
4148
|
-
description: "Side of the offer.",
|
|
4149
|
-
example: "buy"
|
|
4150
|
-
}),
|
|
4151
|
-
obligation_id: z6.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({
|
|
4152
|
-
description: "Offers obligation id",
|
|
4153
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
4154
|
-
})
|
|
4155
|
-
});
|
|
4156
|
-
var GetObligationsQueryParams = z6.object({
|
|
4157
|
-
...PaginationQueryParams.shape,
|
|
4158
|
-
cursor: z6.string().optional().meta({
|
|
4159
|
-
description: "Obligation id cursor",
|
|
4160
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
4161
|
-
})
|
|
4162
|
-
});
|
|
4163
|
-
var schemas = {
|
|
4164
|
-
get_offers: GetOffersQueryParams,
|
|
4165
|
-
get_obligations: GetObligationsQueryParams
|
|
4166
|
-
};
|
|
4167
|
-
function safeParse(action, query, error2) {
|
|
4168
|
-
return schemas[action].safeParse(query, {
|
|
4169
|
-
error: error2
|
|
4170
|
-
});
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
|
-
// src/api/Api/Schema/openapi.ts
|
|
4174
|
-
var successResponseSchema = z.object({
|
|
4175
|
-
status: z.literal("success"),
|
|
4176
|
-
cursor: z.string().nullable(),
|
|
4177
|
-
data: z.array(z.any()),
|
|
4178
|
-
meta: z.object({
|
|
4179
|
-
timestamp: z.string()
|
|
4180
|
-
})
|
|
4181
|
-
});
|
|
4182
|
-
var errorResponseSchema = z.object({
|
|
4183
|
-
status: z.literal("error"),
|
|
4184
|
-
error: z.object({
|
|
4185
|
-
code: z.string(),
|
|
4186
|
-
message: z.string(),
|
|
4187
|
-
details: z.any().optional()
|
|
4188
|
-
}),
|
|
4189
|
-
meta: z.object({
|
|
4190
|
-
timestamp: z.string()
|
|
4191
|
-
})
|
|
4192
|
-
});
|
|
4193
|
-
var paths = {
|
|
4194
|
-
"/v1/offers": {
|
|
4195
|
-
get: {
|
|
4196
|
-
summary: "Offers",
|
|
4197
|
-
description: "Find offers that match specific criteria",
|
|
4198
|
-
tags: ["Offers"],
|
|
4199
|
-
requestParams: {
|
|
4200
|
-
query: GetOffersQueryParams
|
|
4201
|
-
},
|
|
4202
|
-
responses: {
|
|
4203
|
-
200: {
|
|
4204
|
-
description: "Success",
|
|
4205
|
-
content: {
|
|
4206
|
-
"application/json": {
|
|
4207
|
-
schema: successResponseSchema
|
|
4208
|
-
}
|
|
4209
|
-
}
|
|
4210
|
-
},
|
|
4211
|
-
400: {
|
|
4212
|
-
description: "Bad Request",
|
|
4213
|
-
content: {
|
|
4214
|
-
"application/json": {
|
|
4215
|
-
schema: errorResponseSchema
|
|
4216
|
-
}
|
|
4217
|
-
}
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
},
|
|
4222
|
-
"/v1/obligations": {
|
|
4223
|
-
get: {
|
|
4224
|
-
summary: "Obligations",
|
|
4225
|
-
description: "List obligations with pagination support",
|
|
4226
|
-
tags: ["Obligations"],
|
|
4227
|
-
requestParams: {
|
|
4228
|
-
query: GetObligationsQueryParams
|
|
4229
|
-
},
|
|
4230
|
-
responses: {
|
|
4231
|
-
200: {
|
|
4232
|
-
description: "Success",
|
|
4233
|
-
content: {
|
|
4234
|
-
"application/json": {
|
|
4235
|
-
schema: successResponseSchema
|
|
4236
|
-
}
|
|
4237
|
-
}
|
|
4238
|
-
},
|
|
4239
|
-
400: {
|
|
4240
|
-
description: "Bad Request",
|
|
4241
|
-
content: {
|
|
4242
|
-
"application/json": {
|
|
4243
|
-
schema: errorResponseSchema
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
}
|
|
4247
|
-
}
|
|
4248
|
-
}
|
|
4249
|
-
},
|
|
4250
|
-
"/v1/health": {
|
|
4251
|
-
get: {
|
|
4252
|
-
summary: "Router status",
|
|
4253
|
-
description: "Retrieve the aggregated status of the router.",
|
|
4254
|
-
tags: ["Health"],
|
|
4255
|
-
responses: {
|
|
4256
|
-
200: {
|
|
4257
|
-
description: "Success",
|
|
4258
|
-
content: {
|
|
4259
|
-
"application/json": {
|
|
4260
|
-
schema: RouterStatusResponse
|
|
4261
|
-
}
|
|
4262
|
-
}
|
|
4263
|
-
}
|
|
4264
|
-
}
|
|
4265
|
-
}
|
|
4266
|
-
},
|
|
4267
|
-
"/v1/health/collectors": {
|
|
4268
|
-
get: {
|
|
4269
|
-
summary: "Collectors health",
|
|
4270
|
-
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
4271
|
-
tags: ["Health"],
|
|
4272
|
-
responses: {
|
|
4273
|
-
200: {
|
|
4274
|
-
description: "Success",
|
|
4275
|
-
content: {
|
|
4276
|
-
"application/json": {
|
|
4277
|
-
schema: CollectorsHealthResponse
|
|
4278
|
-
}
|
|
4279
|
-
}
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
},
|
|
4284
|
-
"/v1/health/chains": {
|
|
4285
|
-
get: {
|
|
4286
|
-
summary: "Chains health",
|
|
4287
|
-
description: "Retrieve the latest block processed for each chain.",
|
|
4288
|
-
tags: ["Health"],
|
|
4289
|
-
responses: {
|
|
4290
|
-
200: {
|
|
4291
|
-
description: "Success",
|
|
4292
|
-
content: {
|
|
4293
|
-
"application/json": {
|
|
4294
|
-
schema: ChainsHealthResponse
|
|
4295
|
-
}
|
|
4296
|
-
}
|
|
4297
|
-
}
|
|
4298
|
-
}
|
|
4299
|
-
}
|
|
4300
|
-
}
|
|
4301
|
-
};
|
|
4302
|
-
createDocument({
|
|
4303
|
-
openapi: "3.1.0",
|
|
4304
|
-
info: {
|
|
4305
|
-
title: "Router API",
|
|
4306
|
-
version: "1.0.0",
|
|
4307
|
-
description: "API for the Morpho Router"
|
|
4308
|
-
},
|
|
4309
|
-
tags: [
|
|
4310
|
-
{
|
|
4311
|
-
name: "Offers"
|
|
4312
|
-
},
|
|
4313
|
-
{
|
|
4314
|
-
name: "Obligations"
|
|
4315
|
-
},
|
|
4316
|
-
{
|
|
4317
|
-
name: "Health"
|
|
4318
|
-
}
|
|
4319
|
-
],
|
|
4320
|
-
servers: [
|
|
4321
|
-
{
|
|
4322
|
-
url: "https://router.morpho.dev",
|
|
4323
|
-
description: "Production server"
|
|
4324
|
-
},
|
|
4325
|
-
{
|
|
4326
|
-
url: "http://localhost:8081",
|
|
4327
|
-
description: "Local development server"
|
|
4328
|
-
}
|
|
4329
|
-
],
|
|
4330
|
-
paths
|
|
4331
|
-
});
|
|
4332
4509
|
|
|
4333
|
-
// src/api/
|
|
4510
|
+
// src/api/Controllers/getObligations.ts
|
|
4334
4511
|
async function getObligations(queryParameters, store) {
|
|
4335
4512
|
const logger = Logger_exports.getLogger();
|
|
4336
4513
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -4341,8 +4518,20 @@ async function getObligations(queryParameters, store) {
|
|
|
4341
4518
|
cursor: query.cursor,
|
|
4342
4519
|
limit: query.limit
|
|
4343
4520
|
});
|
|
4521
|
+
const quotes = await store.getQuotes({
|
|
4522
|
+
obligationIds: obligations2.map((o) => Obligation_exports.id(o))
|
|
4523
|
+
});
|
|
4344
4524
|
return success({
|
|
4345
|
-
data: obligations2.map(
|
|
4525
|
+
data: obligations2.map(
|
|
4526
|
+
(o) => ObligationResponse_exports.from(
|
|
4527
|
+
o,
|
|
4528
|
+
quotes.find((q) => q.obligationId === Obligation_exports.id(o)) ?? {
|
|
4529
|
+
obligationId: Obligation_exports.id(o),
|
|
4530
|
+
ask: { rate: 0n },
|
|
4531
|
+
bid: { rate: 0n }
|
|
4532
|
+
}
|
|
4533
|
+
)
|
|
4534
|
+
),
|
|
4346
4535
|
cursor: nextCursor ?? null
|
|
4347
4536
|
});
|
|
4348
4537
|
} catch (err) {
|
|
@@ -4356,7 +4545,7 @@ async function getObligations(queryParameters, store) {
|
|
|
4356
4545
|
}
|
|
4357
4546
|
}
|
|
4358
4547
|
|
|
4359
|
-
// src/api/
|
|
4548
|
+
// src/api/Controllers/getOffers.ts
|
|
4360
4549
|
async function getOffers(queryParameters, store) {
|
|
4361
4550
|
const logger = Logger_exports.getLogger();
|
|
4362
4551
|
const result = safeParse("get_offers", queryParameters, (issue) => issue.message);
|
|
@@ -4384,7 +4573,7 @@ async function getOffers(queryParameters, store) {
|
|
|
4384
4573
|
}
|
|
4385
4574
|
}
|
|
4386
4575
|
|
|
4387
|
-
// src/api/Api
|
|
4576
|
+
// src/api/Api.ts
|
|
4388
4577
|
function create5(config) {
|
|
4389
4578
|
return {
|
|
4390
4579
|
serve: ({ port }) => {
|
|
@@ -4416,6 +4605,13 @@ function serve2(parameters) {
|
|
|
4416
4605
|
const { statusCode, body } = await getHealthChains(healthService);
|
|
4417
4606
|
return c.json(body, statusCode);
|
|
4418
4607
|
});
|
|
4608
|
+
app.get(
|
|
4609
|
+
"/docs/swagger.json",
|
|
4610
|
+
(c) => c.text(JSON.stringify(getSwaggerJson()), 200, {
|
|
4611
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
4612
|
+
})
|
|
4613
|
+
);
|
|
4614
|
+
app.get("/docs", (c) => c.html(getDocsHtml(), 200));
|
|
4419
4615
|
serve$1({
|
|
4420
4616
|
fetch: app.fetch,
|
|
4421
4617
|
port: parameters.port
|
|
@@ -5036,6 +5232,64 @@ function create8(config) {
|
|
|
5036
5232
|
const returnedItems = Array.from(items.values());
|
|
5037
5233
|
const nextCursor = returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null;
|
|
5038
5234
|
return { obligations: returnedItems, nextCursor };
|
|
5235
|
+
},
|
|
5236
|
+
getQuotes: async (parameters) => {
|
|
5237
|
+
const { obligationIds } = parameters;
|
|
5238
|
+
if (obligationIds.length === 0) return [];
|
|
5239
|
+
const now2 = time_exports.now();
|
|
5240
|
+
const sumConsumed = db.select({
|
|
5241
|
+
consumed: sql`COALESCE(SUM(${consumed.consumed}), 0)`.as("consumed")
|
|
5242
|
+
}).from(consumed).where(
|
|
5243
|
+
and(
|
|
5244
|
+
eq(consumed.offering, offers.offering),
|
|
5245
|
+
eq(consumed.nonce, offers.nonce),
|
|
5246
|
+
eq(consumed.chainId, offers.chainId)
|
|
5247
|
+
)
|
|
5248
|
+
).as("sum_consumed");
|
|
5249
|
+
const remaining = sql`(${offers.assets} - COALESCE(${sumConsumed.consumed}, 0))`;
|
|
5250
|
+
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
5251
|
+
obligationId: offers.obligationId,
|
|
5252
|
+
rate: offers.rate
|
|
5253
|
+
}).from(offers).leftJoinLateral(sumConsumed, sql`true`).where(
|
|
5254
|
+
and(
|
|
5255
|
+
inArray(offers.obligationId, obligationIds),
|
|
5256
|
+
gte(offers.expiry, now2),
|
|
5257
|
+
gte(offers.maturity, now2),
|
|
5258
|
+
eq(offers.buy, side === "buy"),
|
|
5259
|
+
sql`${remaining} > 0`
|
|
5260
|
+
)
|
|
5261
|
+
).orderBy(
|
|
5262
|
+
offers.obligationId,
|
|
5263
|
+
// lower rates first for buy, higher rates first for sell
|
|
5264
|
+
side === "buy" ? asc(offers.rate) : desc(offers.rate)
|
|
5265
|
+
);
|
|
5266
|
+
const [bestBuys, bestSells] = await Promise.all([
|
|
5267
|
+
query({ side: "buy" }),
|
|
5268
|
+
query({ side: "sell" })
|
|
5269
|
+
]);
|
|
5270
|
+
const quotes = /* @__PURE__ */ new Map();
|
|
5271
|
+
for (const row of bestSells) {
|
|
5272
|
+
quotes.set(row.obligationId, {
|
|
5273
|
+
ask: { rate: row.rate },
|
|
5274
|
+
bid: { rate: 0n }
|
|
5275
|
+
});
|
|
5276
|
+
}
|
|
5277
|
+
for (const row of bestBuys) {
|
|
5278
|
+
const quote = quotes.get(row.obligationId);
|
|
5279
|
+
if (!quote) {
|
|
5280
|
+
quotes.set(row.obligationId, {
|
|
5281
|
+
ask: { rate: 0n },
|
|
5282
|
+
bid: { rate: row.rate }
|
|
5283
|
+
});
|
|
5284
|
+
continue;
|
|
5285
|
+
}
|
|
5286
|
+
quote.bid = { rate: row.rate };
|
|
5287
|
+
}
|
|
5288
|
+
return Array.from(quotes.entries()).map(([id2, quote]) => {
|
|
5289
|
+
return Quote_exports.from({ obligationId: id2, ask: quote.ask, bid: quote.bid });
|
|
5290
|
+
}).sort((a, b) => {
|
|
5291
|
+
return a.obligationId.localeCompare(b.obligationId);
|
|
5292
|
+
});
|
|
5039
5293
|
}
|
|
5040
5294
|
};
|
|
5041
5295
|
}
|
|
@@ -5777,7 +6031,7 @@ function create9(params) {
|
|
|
5777
6031
|
}
|
|
5778
6032
|
|
|
5779
6033
|
// src/services/Services.ts
|
|
5780
|
-
function
|
|
6034
|
+
function from10(config) {
|
|
5781
6035
|
const {
|
|
5782
6036
|
chain,
|
|
5783
6037
|
rpcUrl,
|
|
@@ -5905,7 +6159,7 @@ var RouterCmd = class _RouterCmd extends Command {
|
|
|
5905
6159
|
"RPC URL is required, please set the ROUTER_RPC_URL environment variable or use --rpc-url <url> option."
|
|
5906
6160
|
);
|
|
5907
6161
|
}
|
|
5908
|
-
const routerServices =
|
|
6162
|
+
const routerServices = from10({
|
|
5909
6163
|
chain,
|
|
5910
6164
|
rpcUrl,
|
|
5911
6165
|
dbConfig: {
|