@morpho-dev/router 0.1.15 → 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 -371
- package/dist/cli.js.map +1 -1
- package/dist/index.browser.d.cts +160 -79
- package/dist/index.browser.d.ts +160 -79
- 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 +216 -440
- package/dist/index.node.d.ts +216 -440
- package/dist/index.node.js +5421 -5892
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +5420 -5889
- package/dist/index.node.mjs.map +1 -1
- package/package.json +11 -12
package/dist/cli.js
CHANGED
|
@@ -8,21 +8,19 @@ import { base, mainnet, anvil } from 'viem/chains';
|
|
|
8
8
|
import { getBlock, getLogs } from 'viem/actions';
|
|
9
9
|
import { spawn } from 'child_process';
|
|
10
10
|
import 'fs';
|
|
11
|
-
import 'tevm';
|
|
12
|
-
import 'tevm/common';
|
|
13
11
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
14
12
|
import * as z6 from 'zod';
|
|
15
|
-
import { Base64 } from 'js-base64';
|
|
16
13
|
import { readFile } from 'fs/promises';
|
|
17
14
|
import dotenv from 'dotenv';
|
|
18
15
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
19
16
|
import { serve as serve$1 } from '@hono/node-server';
|
|
20
17
|
import { Hono } from 'hono';
|
|
21
18
|
import { cors } from 'hono/cors';
|
|
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
19
|
import { z } from 'zod/v4';
|
|
25
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';
|
|
26
24
|
import { PGlite } from '@electric-sql/pglite';
|
|
27
25
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
28
26
|
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
@@ -43,7 +41,7 @@ var __export = (target, all) => {
|
|
|
43
41
|
// package.json
|
|
44
42
|
var package_default = {
|
|
45
43
|
name: "@morpho-dev/router",
|
|
46
|
-
version: "0.1.
|
|
44
|
+
version: "0.1.17",
|
|
47
45
|
description: "Router package for Morpho protocol"};
|
|
48
46
|
|
|
49
47
|
// src/core/Chain.ts
|
|
@@ -729,97 +727,6 @@ var from2 = (parameters) => {
|
|
|
729
727
|
};
|
|
730
728
|
};
|
|
731
729
|
|
|
732
|
-
// src/core/Cursor.ts
|
|
733
|
-
var Cursor_exports = {};
|
|
734
|
-
__export(Cursor_exports, {
|
|
735
|
-
decode: () => decode,
|
|
736
|
-
encode: () => encode,
|
|
737
|
-
validate: () => validate
|
|
738
|
-
});
|
|
739
|
-
function validate(cursor) {
|
|
740
|
-
if (!cursor || typeof cursor !== "object") {
|
|
741
|
-
throw new Error("Cursor must be an object");
|
|
742
|
-
}
|
|
743
|
-
const c = cursor;
|
|
744
|
-
if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
|
|
745
|
-
throw new Error(
|
|
746
|
-
`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
if (!["asc", "desc"].includes(c.dir)) {
|
|
750
|
-
throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
|
|
751
|
-
}
|
|
752
|
-
if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
|
|
753
|
-
throw new Error(
|
|
754
|
-
`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
const validations = {
|
|
758
|
-
rate: {
|
|
759
|
-
field: "rate",
|
|
760
|
-
type: "string",
|
|
761
|
-
pattern: /^\d+$/,
|
|
762
|
-
error: "numeric string"
|
|
763
|
-
},
|
|
764
|
-
amount: {
|
|
765
|
-
field: "assets",
|
|
766
|
-
type: "string",
|
|
767
|
-
pattern: /^\d+$/,
|
|
768
|
-
error: "numeric string"
|
|
769
|
-
},
|
|
770
|
-
maturity: {
|
|
771
|
-
field: "maturity",
|
|
772
|
-
type: "number",
|
|
773
|
-
validator: (val) => val > 0,
|
|
774
|
-
error: "positive number"
|
|
775
|
-
},
|
|
776
|
-
expiry: {
|
|
777
|
-
field: "expiry",
|
|
778
|
-
type: "number",
|
|
779
|
-
validator: (val) => val > 0,
|
|
780
|
-
error: "positive number"
|
|
781
|
-
}
|
|
782
|
-
};
|
|
783
|
-
const validation = validations[c.sort];
|
|
784
|
-
if (!validation) {
|
|
785
|
-
throw new Error(`Invalid sort field: ${c.sort}`);
|
|
786
|
-
}
|
|
787
|
-
const fieldValue = c[validation.field];
|
|
788
|
-
if (!fieldValue) {
|
|
789
|
-
throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
|
|
790
|
-
}
|
|
791
|
-
if (typeof fieldValue !== validation.type) {
|
|
792
|
-
throw new Error(
|
|
793
|
-
`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
|
|
794
|
-
);
|
|
795
|
-
}
|
|
796
|
-
if (validation.pattern && !validation.pattern.test(fieldValue)) {
|
|
797
|
-
throw new Error(
|
|
798
|
-
`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
|
|
799
|
-
);
|
|
800
|
-
}
|
|
801
|
-
if (validation.validator && !validation.validator(fieldValue)) {
|
|
802
|
-
throw new Error(
|
|
803
|
-
`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
|
|
804
|
-
);
|
|
805
|
-
}
|
|
806
|
-
if (c.page !== void 0) {
|
|
807
|
-
if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) {
|
|
808
|
-
throw new Error("Invalid page: must be a positive integer");
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
return true;
|
|
812
|
-
}
|
|
813
|
-
function encode(c) {
|
|
814
|
-
return Base64.encodeURL(JSON.stringify(c));
|
|
815
|
-
}
|
|
816
|
-
function decode(token) {
|
|
817
|
-
if (!token) return null;
|
|
818
|
-
const decoded = JSON.parse(Base64.decode(token));
|
|
819
|
-
validate(decoded);
|
|
820
|
-
return decoded;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
730
|
// src/core/Liquidity.ts
|
|
824
731
|
var Liquidity_exports = {};
|
|
825
732
|
__export(Liquidity_exports, {
|
|
@@ -1135,9 +1042,9 @@ __export(Offer_exports, {
|
|
|
1135
1042
|
OfferHashSchema: () => OfferHashSchema,
|
|
1136
1043
|
OfferSchema: () => OfferSchema,
|
|
1137
1044
|
consumedEvent: () => consumedEvent,
|
|
1138
|
-
decode: () =>
|
|
1045
|
+
decode: () => decode,
|
|
1139
1046
|
domain: () => domain,
|
|
1140
|
-
encode: () =>
|
|
1047
|
+
encode: () => encode,
|
|
1141
1048
|
from: () => from5,
|
|
1142
1049
|
fromConsumedLog: () => fromConsumedLog,
|
|
1143
1050
|
fromSnakeCase: () => fromSnakeCase3,
|
|
@@ -1462,7 +1369,7 @@ var OfferAbi = [
|
|
|
1462
1369
|
},
|
|
1463
1370
|
{ name: "signature", type: "bytes" }
|
|
1464
1371
|
];
|
|
1465
|
-
function
|
|
1372
|
+
function encode(offer) {
|
|
1466
1373
|
return encodeAbiParameters(OfferAbi, [
|
|
1467
1374
|
offer.offering,
|
|
1468
1375
|
offer.assets,
|
|
@@ -1479,7 +1386,7 @@ function encode2(offer) {
|
|
|
1479
1386
|
offer.signature ?? "0x"
|
|
1480
1387
|
]);
|
|
1481
1388
|
}
|
|
1482
|
-
function
|
|
1389
|
+
function decode(data, blockNumber) {
|
|
1483
1390
|
let decoded;
|
|
1484
1391
|
try {
|
|
1485
1392
|
decoded = decodeAbiParameters(OfferAbi, data);
|
|
@@ -1549,6 +1456,57 @@ var AccountNotSetError = class extends BaseError {
|
|
|
1549
1456
|
}
|
|
1550
1457
|
};
|
|
1551
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
|
+
|
|
1552
1510
|
// src/evm/EVM.ts
|
|
1553
1511
|
var users = [
|
|
1554
1512
|
privateKeyToAccount(
|
|
@@ -1665,11 +1623,16 @@ function defaultLogger(minLevel, pretty) {
|
|
|
1665
1623
|
return;
|
|
1666
1624
|
}
|
|
1667
1625
|
const { msg, ...rest } = entry;
|
|
1626
|
+
const stack = typeof rest.stack === "string" ? rest.stack : void 0;
|
|
1627
|
+
if (stack) delete rest.stack;
|
|
1668
1628
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
1669
1629
|
const level = methodLevel.toUpperCase();
|
|
1670
1630
|
const extras = Object.entries(rest).map(([k, v]) => `${k}=${formatValue(v)}`).join(" ");
|
|
1671
1631
|
const line = extras.length > 0 ? `${timestamp2} [${level}] ${msg} ${extras}` : `${timestamp2} [${level}] ${msg}`;
|
|
1672
1632
|
console[consoleMethod](line);
|
|
1633
|
+
if (stack) {
|
|
1634
|
+
console[consoleMethod](stack);
|
|
1635
|
+
}
|
|
1673
1636
|
} : () => {
|
|
1674
1637
|
};
|
|
1675
1638
|
return {
|
|
@@ -1711,6 +1674,442 @@ function formatValue(value) {
|
|
|
1711
1674
|
}
|
|
1712
1675
|
}
|
|
1713
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
|
+
}
|
|
1714
2113
|
|
|
1715
2114
|
// src/collectors/index.ts
|
|
1716
2115
|
var collectors_exports = {};
|
|
@@ -1993,20 +2392,31 @@ function create2({
|
|
|
1993
2392
|
});
|
|
1994
2393
|
return poll(
|
|
1995
2394
|
async () => {
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
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
|
+
}
|
|
2010
2420
|
},
|
|
2011
2421
|
{ interval: options.interval }
|
|
2012
2422
|
);
|
|
@@ -2026,7 +2436,7 @@ function start(collector) {
|
|
|
2026
2436
|
}
|
|
2027
2437
|
var DEFAULT_BATCH_SIZE2 = 100;
|
|
2028
2438
|
var DEFAULT_BLOCK_WINDOW2 = 100;
|
|
2029
|
-
function
|
|
2439
|
+
function from7(parameters) {
|
|
2030
2440
|
const config = {
|
|
2031
2441
|
client: parameters.client,
|
|
2032
2442
|
mempoolAddress: parameters.mempoolAddress,
|
|
@@ -2168,7 +2578,7 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
2168
2578
|
|
|
2169
2579
|
// src/mempool/MempoolClient.ts
|
|
2170
2580
|
function connect(parameters) {
|
|
2171
|
-
return
|
|
2581
|
+
return from7(parameters);
|
|
2172
2582
|
}
|
|
2173
2583
|
|
|
2174
2584
|
// src/stores/CollectorStore.ts
|
|
@@ -4008,7 +4418,7 @@ function handleZodError(error2) {
|
|
|
4008
4418
|
return new ValidationError("Validation failed", formattedErrors);
|
|
4009
4419
|
}
|
|
4010
4420
|
|
|
4011
|
-
// src/api/
|
|
4421
|
+
// src/api/Controllers/getHealth.ts
|
|
4012
4422
|
async function getHealth(healthService) {
|
|
4013
4423
|
const logger = Logger_exports.getLogger();
|
|
4014
4424
|
try {
|
|
@@ -4073,266 +4483,31 @@ async function getHealthCollectors(healthService) {
|
|
|
4073
4483
|
return error(err);
|
|
4074
4484
|
}
|
|
4075
4485
|
}
|
|
4076
|
-
var CollectorHealth = z.object({
|
|
4077
|
-
name: z.string(),
|
|
4078
|
-
chain_id: z.number(),
|
|
4079
|
-
block_number: z.number().nullable(),
|
|
4080
|
-
updated_at: z.string().nullable(),
|
|
4081
|
-
lag: z.number().nullable(),
|
|
4082
|
-
status: z.enum(["live", "lagging", "unknown"])
|
|
4083
|
-
});
|
|
4084
|
-
var CollectorsHealthResponse = z.object({
|
|
4085
|
-
collectors: z.array(CollectorHealth)
|
|
4086
|
-
});
|
|
4087
|
-
var ChainHealth = z.object({
|
|
4088
|
-
chain_id: z.number(),
|
|
4089
|
-
block_number: z.number(),
|
|
4090
|
-
updated_at: z.string()
|
|
4091
|
-
});
|
|
4092
|
-
var ChainsHealthResponse = z.object({
|
|
4093
|
-
chains: z.array(ChainHealth)
|
|
4094
|
-
});
|
|
4095
|
-
var RouterStatusResponse = z.object({
|
|
4096
|
-
status: z.enum(["live", "syncing"])
|
|
4097
|
-
});
|
|
4098
4486
|
|
|
4099
|
-
// src/api/
|
|
4487
|
+
// src/api/Schema/ObligationResponse.ts
|
|
4100
4488
|
var ObligationResponse_exports = {};
|
|
4101
4489
|
__export(ObligationResponse_exports, {
|
|
4102
|
-
from: () =>
|
|
4490
|
+
from: () => from8
|
|
4103
4491
|
});
|
|
4104
|
-
function
|
|
4105
|
-
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
|
+
});
|
|
4106
4499
|
}
|
|
4107
4500
|
|
|
4108
|
-
// src/api/
|
|
4501
|
+
// src/api/Schema/OfferResponse.ts
|
|
4109
4502
|
var OfferResponse_exports = {};
|
|
4110
4503
|
__export(OfferResponse_exports, {
|
|
4111
|
-
from: () =>
|
|
4504
|
+
from: () => from9
|
|
4112
4505
|
});
|
|
4113
|
-
function
|
|
4506
|
+
function from9(offer) {
|
|
4114
4507
|
return toSnakeCase(offer);
|
|
4115
4508
|
}
|
|
4116
|
-
var MAX_LIMIT = 100;
|
|
4117
|
-
var DEFAULT_LIMIT = 20;
|
|
4118
|
-
var PaginationQueryParams = z6.object({
|
|
4119
|
-
cursor: z6.string().optional().refine(
|
|
4120
|
-
(val) => {
|
|
4121
|
-
if (!val) return true;
|
|
4122
|
-
try {
|
|
4123
|
-
const decoded = Cursor_exports.decode(val);
|
|
4124
|
-
return decoded !== null;
|
|
4125
|
-
} catch (_error) {
|
|
4126
|
-
return false;
|
|
4127
|
-
}
|
|
4128
|
-
},
|
|
4129
|
-
{
|
|
4130
|
-
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
4131
|
-
}
|
|
4132
|
-
).meta({
|
|
4133
|
-
description: "Pagination cursor in base64url-encoded format",
|
|
4134
|
-
example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
|
|
4135
|
-
}),
|
|
4136
|
-
limit: z6.string().regex(/^[1-9]\d*$/, {
|
|
4137
|
-
message: "Limit must be a positive integer"
|
|
4138
|
-
}).transform((val) => Number.parseInt(val, 10)).pipe(
|
|
4139
|
-
z6.number().max(MAX_LIMIT, {
|
|
4140
|
-
message: `Limit cannot exceed ${MAX_LIMIT}`
|
|
4141
|
-
})
|
|
4142
|
-
).optional().default(DEFAULT_LIMIT).meta({
|
|
4143
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
|
|
4144
|
-
example: 10
|
|
4145
|
-
})
|
|
4146
|
-
});
|
|
4147
|
-
var GetOffersQueryParams = z6.object({
|
|
4148
|
-
...PaginationQueryParams.shape,
|
|
4149
|
-
side: z6.enum(["buy", "sell"]).meta({
|
|
4150
|
-
description: "Side of the offer.",
|
|
4151
|
-
example: "buy"
|
|
4152
|
-
}),
|
|
4153
|
-
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({
|
|
4154
|
-
description: "Offers obligation id",
|
|
4155
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
4156
|
-
})
|
|
4157
|
-
});
|
|
4158
|
-
var GetObligationsQueryParams = z6.object({
|
|
4159
|
-
...PaginationQueryParams.shape,
|
|
4160
|
-
cursor: z6.string().optional().meta({
|
|
4161
|
-
description: "Obligation id cursor",
|
|
4162
|
-
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
4163
|
-
})
|
|
4164
|
-
});
|
|
4165
|
-
var schemas = {
|
|
4166
|
-
get_offers: GetOffersQueryParams,
|
|
4167
|
-
get_obligations: GetObligationsQueryParams
|
|
4168
|
-
};
|
|
4169
|
-
function safeParse(action, query, error2) {
|
|
4170
|
-
return schemas[action].safeParse(query, {
|
|
4171
|
-
error: error2
|
|
4172
|
-
});
|
|
4173
|
-
}
|
|
4174
|
-
|
|
4175
|
-
// src/api/Api/Schema/openapi.ts
|
|
4176
|
-
var successResponseSchema = z.object({
|
|
4177
|
-
status: z.literal("success"),
|
|
4178
|
-
cursor: z.string().nullable(),
|
|
4179
|
-
data: z.array(z.any()),
|
|
4180
|
-
meta: z.object({
|
|
4181
|
-
timestamp: z.string()
|
|
4182
|
-
})
|
|
4183
|
-
});
|
|
4184
|
-
var errorResponseSchema = z.object({
|
|
4185
|
-
status: z.literal("error"),
|
|
4186
|
-
error: z.object({
|
|
4187
|
-
code: z.string(),
|
|
4188
|
-
message: z.string(),
|
|
4189
|
-
details: z.any().optional()
|
|
4190
|
-
}),
|
|
4191
|
-
meta: z.object({
|
|
4192
|
-
timestamp: z.string()
|
|
4193
|
-
})
|
|
4194
|
-
});
|
|
4195
|
-
var paths = {
|
|
4196
|
-
"/v1/offers": {
|
|
4197
|
-
get: {
|
|
4198
|
-
summary: "Offers",
|
|
4199
|
-
description: "Find offers that match specific criteria",
|
|
4200
|
-
tags: ["Offers"],
|
|
4201
|
-
requestParams: {
|
|
4202
|
-
query: GetOffersQueryParams
|
|
4203
|
-
},
|
|
4204
|
-
responses: {
|
|
4205
|
-
200: {
|
|
4206
|
-
description: "Success",
|
|
4207
|
-
content: {
|
|
4208
|
-
"application/json": {
|
|
4209
|
-
schema: successResponseSchema
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
},
|
|
4213
|
-
400: {
|
|
4214
|
-
description: "Bad Request",
|
|
4215
|
-
content: {
|
|
4216
|
-
"application/json": {
|
|
4217
|
-
schema: errorResponseSchema
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
}
|
|
4222
|
-
}
|
|
4223
|
-
},
|
|
4224
|
-
"/v1/obligations": {
|
|
4225
|
-
get: {
|
|
4226
|
-
summary: "Obligations",
|
|
4227
|
-
description: "List obligations with pagination support",
|
|
4228
|
-
tags: ["Obligations"],
|
|
4229
|
-
requestParams: {
|
|
4230
|
-
query: GetObligationsQueryParams
|
|
4231
|
-
},
|
|
4232
|
-
responses: {
|
|
4233
|
-
200: {
|
|
4234
|
-
description: "Success",
|
|
4235
|
-
content: {
|
|
4236
|
-
"application/json": {
|
|
4237
|
-
schema: successResponseSchema
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
},
|
|
4241
|
-
400: {
|
|
4242
|
-
description: "Bad Request",
|
|
4243
|
-
content: {
|
|
4244
|
-
"application/json": {
|
|
4245
|
-
schema: errorResponseSchema
|
|
4246
|
-
}
|
|
4247
|
-
}
|
|
4248
|
-
}
|
|
4249
|
-
}
|
|
4250
|
-
}
|
|
4251
|
-
},
|
|
4252
|
-
"/v1/health": {
|
|
4253
|
-
get: {
|
|
4254
|
-
summary: "Router status",
|
|
4255
|
-
description: "Retrieve the aggregated status of the router.",
|
|
4256
|
-
tags: ["Health"],
|
|
4257
|
-
responses: {
|
|
4258
|
-
200: {
|
|
4259
|
-
description: "Success",
|
|
4260
|
-
content: {
|
|
4261
|
-
"application/json": {
|
|
4262
|
-
schema: RouterStatusResponse
|
|
4263
|
-
}
|
|
4264
|
-
}
|
|
4265
|
-
}
|
|
4266
|
-
}
|
|
4267
|
-
}
|
|
4268
|
-
},
|
|
4269
|
-
"/v1/health/collectors": {
|
|
4270
|
-
get: {
|
|
4271
|
-
summary: "Collectors health",
|
|
4272
|
-
description: "Retrieve the block numbers processed by collectors and their sync status.",
|
|
4273
|
-
tags: ["Health"],
|
|
4274
|
-
responses: {
|
|
4275
|
-
200: {
|
|
4276
|
-
description: "Success",
|
|
4277
|
-
content: {
|
|
4278
|
-
"application/json": {
|
|
4279
|
-
schema: CollectorsHealthResponse
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4284
|
-
}
|
|
4285
|
-
},
|
|
4286
|
-
"/v1/health/chains": {
|
|
4287
|
-
get: {
|
|
4288
|
-
summary: "Chains health",
|
|
4289
|
-
description: "Retrieve the latest block processed for each chain.",
|
|
4290
|
-
tags: ["Health"],
|
|
4291
|
-
responses: {
|
|
4292
|
-
200: {
|
|
4293
|
-
description: "Success",
|
|
4294
|
-
content: {
|
|
4295
|
-
"application/json": {
|
|
4296
|
-
schema: ChainsHealthResponse
|
|
4297
|
-
}
|
|
4298
|
-
}
|
|
4299
|
-
}
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4302
|
-
}
|
|
4303
|
-
};
|
|
4304
|
-
createDocument({
|
|
4305
|
-
openapi: "3.1.0",
|
|
4306
|
-
info: {
|
|
4307
|
-
title: "Router API",
|
|
4308
|
-
version: "1.0.0",
|
|
4309
|
-
description: "API for the Morpho Router"
|
|
4310
|
-
},
|
|
4311
|
-
tags: [
|
|
4312
|
-
{
|
|
4313
|
-
name: "Offers"
|
|
4314
|
-
},
|
|
4315
|
-
{
|
|
4316
|
-
name: "Obligations"
|
|
4317
|
-
},
|
|
4318
|
-
{
|
|
4319
|
-
name: "Health"
|
|
4320
|
-
}
|
|
4321
|
-
],
|
|
4322
|
-
servers: [
|
|
4323
|
-
{
|
|
4324
|
-
url: "https://router.morpho.dev",
|
|
4325
|
-
description: "Production server"
|
|
4326
|
-
},
|
|
4327
|
-
{
|
|
4328
|
-
url: "http://localhost:8081",
|
|
4329
|
-
description: "Local development server"
|
|
4330
|
-
}
|
|
4331
|
-
],
|
|
4332
|
-
paths
|
|
4333
|
-
});
|
|
4334
4509
|
|
|
4335
|
-
// src/api/
|
|
4510
|
+
// src/api/Controllers/getObligations.ts
|
|
4336
4511
|
async function getObligations(queryParameters, store) {
|
|
4337
4512
|
const logger = Logger_exports.getLogger();
|
|
4338
4513
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -4343,8 +4518,20 @@ async function getObligations(queryParameters, store) {
|
|
|
4343
4518
|
cursor: query.cursor,
|
|
4344
4519
|
limit: query.limit
|
|
4345
4520
|
});
|
|
4521
|
+
const quotes = await store.getQuotes({
|
|
4522
|
+
obligationIds: obligations2.map((o) => Obligation_exports.id(o))
|
|
4523
|
+
});
|
|
4346
4524
|
return success({
|
|
4347
|
-
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
|
+
),
|
|
4348
4535
|
cursor: nextCursor ?? null
|
|
4349
4536
|
});
|
|
4350
4537
|
} catch (err) {
|
|
@@ -4358,7 +4545,7 @@ async function getObligations(queryParameters, store) {
|
|
|
4358
4545
|
}
|
|
4359
4546
|
}
|
|
4360
4547
|
|
|
4361
|
-
// src/api/
|
|
4548
|
+
// src/api/Controllers/getOffers.ts
|
|
4362
4549
|
async function getOffers(queryParameters, store) {
|
|
4363
4550
|
const logger = Logger_exports.getLogger();
|
|
4364
4551
|
const result = safeParse("get_offers", queryParameters, (issue) => issue.message);
|
|
@@ -4386,7 +4573,7 @@ async function getOffers(queryParameters, store) {
|
|
|
4386
4573
|
}
|
|
4387
4574
|
}
|
|
4388
4575
|
|
|
4389
|
-
// src/api/Api
|
|
4576
|
+
// src/api/Api.ts
|
|
4390
4577
|
function create5(config) {
|
|
4391
4578
|
return {
|
|
4392
4579
|
serve: ({ port }) => {
|
|
@@ -4418,6 +4605,13 @@ function serve2(parameters) {
|
|
|
4418
4605
|
const { statusCode, body } = await getHealthChains(healthService);
|
|
4419
4606
|
return c.json(body, statusCode);
|
|
4420
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));
|
|
4421
4615
|
serve$1({
|
|
4422
4616
|
fetch: app.fetch,
|
|
4423
4617
|
port: parameters.port
|
|
@@ -5038,6 +5232,64 @@ function create8(config) {
|
|
|
5038
5232
|
const returnedItems = Array.from(items.values());
|
|
5039
5233
|
const nextCursor = returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null;
|
|
5040
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
|
+
});
|
|
5041
5293
|
}
|
|
5042
5294
|
};
|
|
5043
5295
|
}
|
|
@@ -5779,7 +6031,7 @@ function create9(params) {
|
|
|
5779
6031
|
}
|
|
5780
6032
|
|
|
5781
6033
|
// src/services/Services.ts
|
|
5782
|
-
function
|
|
6034
|
+
function from10(config) {
|
|
5783
6035
|
const {
|
|
5784
6036
|
chain,
|
|
5785
6037
|
rpcUrl,
|
|
@@ -5907,7 +6159,7 @@ var RouterCmd = class _RouterCmd extends Command {
|
|
|
5907
6159
|
"RPC URL is required, please set the ROUTER_RPC_URL environment variable or use --rpc-url <url> option."
|
|
5908
6160
|
);
|
|
5909
6161
|
}
|
|
5910
|
-
const routerServices =
|
|
6162
|
+
const routerServices = from10({
|
|
5911
6163
|
chain,
|
|
5912
6164
|
rpcUrl,
|
|
5913
6165
|
dbConfig: {
|