@morpho-dev/router 0.1.3 → 0.1.5

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.
@@ -1,9 +1,9 @@
1
- import { Errors, LLTV, Offer, Format, Time, Maturity } from '@morpho-dev/mempool';
1
+ import { Errors, LLTV, Offer, Format, Time, Maturity, Utils } from '@morpho-dev/mempool';
2
2
  export * from '@morpho-dev/mempool';
3
+ import { Base64 } from 'js-base64';
3
4
  import { z } from 'zod/v4';
4
5
  import { createDocument } from 'zod-openapi';
5
- import { parseUnits, maxUint256, formatUnits } from 'viem';
6
- import { Base64 } from 'js-base64';
6
+ import { parseUnits, maxUint256, formatUnits, erc20Abi } from 'viem';
7
7
  import { serve as serve$1 } from '@hono/node-server';
8
8
  import { Hono } from 'hono';
9
9
  import { AsyncLocalStorage } from 'async_hooks';
@@ -14,6 +14,145 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
+ // src/Callback.ts
18
+ var Callback_exports = {};
19
+ __export(Callback_exports, {
20
+ CallbackType: () => CallbackType,
21
+ buildLiquidity: () => buildLiquidity,
22
+ getCallbackIdForOffer: () => getCallbackIdForOffer
23
+ });
24
+ var CallbackType = /* @__PURE__ */ ((CallbackType2) => {
25
+ CallbackType2["BuyWithEmptyCallback"] = "buy_with_empty_callback";
26
+ return CallbackType2;
27
+ })(CallbackType || {});
28
+ function buildLiquidity(parameters) {
29
+ const { type, user, contract, chainId, amount, index = 0, updatedAt = /* @__PURE__ */ new Date() } = parameters;
30
+ if (type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */)
31
+ throw new Error(`CallbackType not implemented: ${type}`);
32
+ const amountStr = amount.toString();
33
+ const id = `${user}-${chainId.toString()}-${type}-${contract}`.toLowerCase();
34
+ return {
35
+ userPosition: {
36
+ id,
37
+ availableLiquidityQueueId: id,
38
+ user: user.toLowerCase(),
39
+ chainId,
40
+ amount: amountStr,
41
+ updatedAt
42
+ },
43
+ queues: [
44
+ {
45
+ queue: {
46
+ queueId: id,
47
+ availableLiquidityPoolId: id,
48
+ index,
49
+ updatedAt
50
+ },
51
+ pool: {
52
+ id,
53
+ amount: amountStr,
54
+ updatedAt
55
+ }
56
+ }
57
+ ]
58
+ };
59
+ }
60
+ function getCallbackIdForOffer(offer) {
61
+ if (offer.buy && offer.callback.data === "0x") {
62
+ const type = "buy_with_empty_callback" /* BuyWithEmptyCallback */;
63
+ const user = offer.offering;
64
+ const loanToken = offer.loanToken;
65
+ return `${user}-${offer.chainId.toString()}-${type}-${loanToken}`.toLowerCase();
66
+ }
67
+ return null;
68
+ }
69
+
70
+ // src/Cursor.ts
71
+ var Cursor_exports = {};
72
+ __export(Cursor_exports, {
73
+ decode: () => decode,
74
+ encode: () => encode,
75
+ validate: () => validate
76
+ });
77
+ function validate(cursor) {
78
+ if (!cursor || typeof cursor !== "object") {
79
+ throw new Error("Cursor must be an object");
80
+ }
81
+ const c = cursor;
82
+ if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
83
+ throw new Error(
84
+ `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
85
+ );
86
+ }
87
+ if (!["asc", "desc"].includes(c.dir)) {
88
+ throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
89
+ }
90
+ if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
91
+ throw new Error(
92
+ `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
93
+ );
94
+ }
95
+ const validations = {
96
+ rate: {
97
+ field: "rate",
98
+ type: "string",
99
+ pattern: /^\d+$/,
100
+ error: "numeric string"
101
+ },
102
+ amount: {
103
+ field: "assets",
104
+ type: "string",
105
+ pattern: /^\d+$/,
106
+ error: "numeric string"
107
+ },
108
+ maturity: {
109
+ field: "maturity",
110
+ type: "number",
111
+ validator: (val) => val > 0,
112
+ error: "positive number"
113
+ },
114
+ expiry: {
115
+ field: "expiry",
116
+ type: "number",
117
+ validator: (val) => val > 0,
118
+ error: "positive number"
119
+ }
120
+ };
121
+ const validation = validations[c.sort];
122
+ if (!validation) {
123
+ throw new Error(`Invalid sort field: ${c.sort}`);
124
+ }
125
+ const fieldValue = c[validation.field];
126
+ if (!fieldValue) {
127
+ throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
128
+ }
129
+ if (typeof fieldValue !== validation.type) {
130
+ throw new Error(
131
+ `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
132
+ );
133
+ }
134
+ if (validation.pattern && !validation.pattern.test(fieldValue)) {
135
+ throw new Error(
136
+ `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
137
+ );
138
+ }
139
+ if (validation.validator && !validation.validator(fieldValue)) {
140
+ throw new Error(
141
+ `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
142
+ );
143
+ }
144
+ return true;
145
+ }
146
+ function encode(c) {
147
+ return Base64.encodeURL(JSON.stringify(c));
148
+ }
149
+ function decode(token) {
150
+ if (!token) return null;
151
+ const decoded = JSON.parse(Base64.decode(token));
152
+ validate(decoded);
153
+ return decoded;
154
+ }
155
+
17
156
  // src/core/apiSchema/index.ts
18
157
  var apiSchema_exports = {};
19
158
  __export(apiSchema_exports, {
@@ -104,140 +243,6 @@ var InvalidRouterOfferError = class extends Errors.BaseError {
104
243
  }
105
244
  };
106
245
 
107
- // src/utils/index.ts
108
- var utils_exports = {};
109
- __export(utils_exports, {
110
- batch: () => batch,
111
- decodeCursor: () => decodeCursor,
112
- encodeCursor: () => encodeCursor,
113
- poll: () => poll,
114
- retry: () => retry,
115
- validateCursor: () => validateCursor,
116
- wait: () => wait
117
- });
118
-
119
- // src/utils/batch.ts
120
- function* batch(array, batchSize) {
121
- for (let i = 0; i < array.length; i += batchSize) {
122
- yield array.slice(i, i + batchSize);
123
- }
124
- }
125
- function validateCursor(cursor) {
126
- if (!cursor || typeof cursor !== "object") {
127
- throw new Error("Cursor must be an object");
128
- }
129
- const c = cursor;
130
- if (!["rate", "maturity", "expiry", "amount"].includes(c.sort)) {
131
- throw new Error(
132
- `Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`
133
- );
134
- }
135
- if (!["asc", "desc"].includes(c.dir)) {
136
- throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
137
- }
138
- if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) {
139
- throw new Error(
140
- `Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`
141
- );
142
- }
143
- const validations = {
144
- rate: {
145
- field: "rate",
146
- type: "string",
147
- pattern: /^\d+$/,
148
- error: "numeric string"
149
- },
150
- amount: {
151
- field: "assets",
152
- type: "string",
153
- pattern: /^\d+$/,
154
- error: "numeric string"
155
- },
156
- maturity: {
157
- field: "maturity",
158
- type: "number",
159
- validator: (val) => val > 0,
160
- error: "positive number"
161
- },
162
- expiry: {
163
- field: "expiry",
164
- type: "number",
165
- validator: (val) => val > 0,
166
- error: "positive number"
167
- }
168
- };
169
- const validation = validations[c.sort];
170
- if (!validation) {
171
- throw new Error(`Invalid sort field: ${c.sort}`);
172
- }
173
- const fieldValue = c[validation.field];
174
- if (!fieldValue) {
175
- throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
176
- }
177
- if (typeof fieldValue !== validation.type) {
178
- throw new Error(
179
- `${c.sort} sort requires '${validation.field}' field of type ${validation.type}`
180
- );
181
- }
182
- if (validation.pattern && !validation.pattern.test(fieldValue)) {
183
- throw new Error(
184
- `Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`
185
- );
186
- }
187
- if (validation.validator && !validation.validator(fieldValue)) {
188
- throw new Error(
189
- `Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`
190
- );
191
- }
192
- return true;
193
- }
194
- function encodeCursor(c) {
195
- return Base64.encodeURL(JSON.stringify(c));
196
- }
197
- function decodeCursor(token) {
198
- if (!token) return null;
199
- const decoded = JSON.parse(Base64.decode(token));
200
- validateCursor(decoded);
201
- return decoded;
202
- }
203
-
204
- // src/utils/wait.ts
205
- async function wait(time) {
206
- return new Promise((res) => setTimeout(res, time));
207
- }
208
-
209
- // src/utils/poll.ts
210
- function poll(fn, { interval }) {
211
- let active = true;
212
- const unwatch = () => active = false;
213
- const watch = async () => {
214
- await wait(interval);
215
- const poll2 = async () => {
216
- if (!active) return;
217
- await fn({ unpoll: unwatch });
218
- await wait(interval);
219
- poll2();
220
- };
221
- poll2();
222
- };
223
- watch();
224
- return unwatch;
225
- }
226
-
227
- // src/utils/retry.ts
228
- var retry = async (fn, attempts = 3, delayMs = 50) => {
229
- let lastErr;
230
- for (let i = 0; i < attempts; i++) {
231
- try {
232
- return await fn();
233
- } catch (err) {
234
- lastErr = err;
235
- if (i < attempts - 1) await new Promise((r) => setTimeout(r, delayMs));
236
- }
237
- }
238
- throw lastErr;
239
- };
240
-
241
246
  // src/core/apiSchema/requests.ts
242
247
  var MAX_LIMIT = 100;
243
248
  var DEFAULT_LIMIT = 20;
@@ -415,7 +420,7 @@ var GetOffersQueryParams = z.object({
415
420
  (val) => {
416
421
  if (!val) return true;
417
422
  try {
418
- const decoded = decodeCursor(val);
423
+ const decoded = decode(val);
419
424
  return decoded !== null;
420
425
  } catch (_error) {
421
426
  return false;
@@ -582,21 +587,12 @@ var MatchOffersQueryParams = z.object({
582
587
  description: "Filter by a specific offer creator address",
583
588
  example: "0x1234567890123456789012345678901234567890"
584
589
  }),
585
- // Status filtering
586
- status: z.string().regex(/^[a-zA-Z_]+(,[a-zA-Z_]+)*$/, {
587
- message: "Status must be comma-separated status values"
588
- }).transform((val) => val.split(",")).refine((statuses) => statuses.every((status) => OfferStatusValues.includes(status)), {
589
- message: `Invalid status value. Must be one of: ${OfferStatusValues.join(", ")}`
590
- }).optional().meta({
591
- description: `Filter by multiple statuses (comma-separated). Valid values: ${OfferStatusValues.join(", ")}. By default, only offers with 'valid' status are returned.`,
592
- example: "valid,callback_error"
593
- }),
594
590
  // Pagination
595
591
  cursor: z.string().optional().refine(
596
592
  (val) => {
597
593
  if (!val) return true;
598
594
  try {
599
- const decoded = decodeCursor(val);
595
+ const decoded = decode(val);
600
596
  return decoded !== null;
601
597
  } catch (_error) {
602
598
  return false;
@@ -1023,8 +1019,10 @@ function memory(parameters) {
1023
1019
  const consumedIds = /* @__PURE__ */ new Set();
1024
1020
  const create = async (parameters2) => {
1025
1021
  if (map.has(parameters2.offer.hash.toLowerCase())) return parameters2.offer.hash;
1022
+ const callbackId = getCallbackIdForOffer(parameters2.offer);
1026
1023
  map.set(parameters2.offer.hash.toLowerCase(), {
1027
1024
  ...parameters2.offer,
1025
+ ...callbackId ? { callbackId } : {},
1028
1026
  status: parameters2.status,
1029
1027
  metadata: parameters2.metadata
1030
1028
  });
@@ -1119,7 +1117,7 @@ function memory(parameters) {
1119
1117
  ...o,
1120
1118
  consumed: filled.get(o.chainId)?.get(o.offering.toLowerCase())?.get(o.nonce) || 0n
1121
1119
  })).filter((o) => o.consumed < o.assets);
1122
- const cursor = decodeCursor(queryCursor);
1120
+ const cursor = decode(queryCursor);
1123
1121
  if (cursor) {
1124
1122
  if (cursor.sort !== sortBy || cursor.dir !== sortOrder) {
1125
1123
  throw new Error("Cursor does not match the current sort parameters");
@@ -1217,11 +1215,35 @@ function memory(parameters) {
1217
1215
  default:
1218
1216
  base.expiry = last.expiry;
1219
1217
  }
1220
- nextCursor = encodeCursor(base);
1218
+ nextCursor = encode(base);
1221
1219
  }
1222
1220
  offers = offers.slice(0, limit);
1221
+ const data = offers.map((o) => ({
1222
+ ...Offer.from({
1223
+ offering: o.offering,
1224
+ assets: o.assets,
1225
+ rate: o.rate,
1226
+ maturity: Maturity.from(o.maturity),
1227
+ expiry: o.expiry,
1228
+ start: o.start,
1229
+ nonce: o.nonce,
1230
+ buy: o.buy,
1231
+ chainId: o.chainId,
1232
+ loanToken: o.loanToken,
1233
+ collaterals: o.collaterals.map((c) => ({ asset: c.asset, oracle: c.oracle, lltv: c.lltv })).sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),
1234
+ callback: {
1235
+ address: o.callback.address,
1236
+ data: o.callback.data,
1237
+ gasLimit: o.callback.gasLimit
1238
+ },
1239
+ ...o.signature !== null && o.signature !== void 0 ? { signature: o.signature } : {}
1240
+ }),
1241
+ consumed: o.consumed,
1242
+ status: o.status,
1243
+ ...o.metadata ? { metadata: o.metadata } : {}
1244
+ }));
1223
1245
  return {
1224
- offers,
1246
+ offers: data,
1225
1247
  nextCursor
1226
1248
  };
1227
1249
  },
@@ -1236,7 +1258,6 @@ function memory(parameters) {
1236
1258
  maxMaturity,
1237
1259
  loanToken,
1238
1260
  creator,
1239
- status,
1240
1261
  cursor: queryCursor,
1241
1262
  limit = 20
1242
1263
  } = params;
@@ -1247,7 +1268,7 @@ function memory(parameters) {
1247
1268
  ...o,
1248
1269
  consumed: filled.get(o.chainId)?.get(o.offering.toLowerCase())?.get(o.nonce) || 0n
1249
1270
  })).filter((o) => o.consumed < o.assets);
1250
- const cursor = decodeCursor(queryCursor);
1271
+ const cursor = decode(queryCursor);
1251
1272
  if (cursor) {
1252
1273
  if (cursor.sort !== "rate" || cursor.dir !== sortOrder) {
1253
1274
  throw new Error("Cursor does not match the current sort parameters");
@@ -1282,7 +1303,7 @@ function memory(parameters) {
1282
1303
  maxMaturity && (offers = offers.filter((o) => o.maturity <= maxMaturity));
1283
1304
  loanToken && (offers = offers.filter((o) => o.loanToken.toLowerCase() === loanToken.toLowerCase()));
1284
1305
  creator && (offers = offers.filter((o) => o.offering.toLowerCase() === creator.toLowerCase()));
1285
- status && (offers = offers.filter((o) => status.includes(o.status)));
1306
+ offers = offers.filter((o) => ["valid"].includes(o.status));
1286
1307
  const byGroup = /* @__PURE__ */ new Map();
1287
1308
  for (const offer of offers) {
1288
1309
  const groupKey = `${offer.chainId}-${offer.offering.toLowerCase()}-${offer.nonce}-${offer.buy}`;
@@ -1317,7 +1338,7 @@ function memory(parameters) {
1317
1338
  let nextCursor = null;
1318
1339
  if (offers.length > limit) {
1319
1340
  const last = offers[limit - 1];
1320
- nextCursor = encodeCursor({
1341
+ nextCursor = encode({
1321
1342
  sort: "rate",
1322
1343
  dir: sortOrder,
1323
1344
  hash: last.hash,
@@ -1325,8 +1346,32 @@ function memory(parameters) {
1325
1346
  });
1326
1347
  }
1327
1348
  offers = offers.slice(0, limit);
1349
+ const data = offers.map((o) => ({
1350
+ ...Offer.from({
1351
+ offering: o.offering,
1352
+ assets: o.assets,
1353
+ rate: o.rate,
1354
+ maturity: Maturity.from(o.maturity),
1355
+ expiry: o.expiry,
1356
+ start: o.start,
1357
+ nonce: o.nonce,
1358
+ buy: o.buy,
1359
+ chainId: o.chainId,
1360
+ loanToken: o.loanToken,
1361
+ collaterals: o.collaterals.map((c) => ({ asset: c.asset, oracle: c.oracle, lltv: c.lltv })).sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())),
1362
+ callback: {
1363
+ address: o.callback.address,
1364
+ data: o.callback.data,
1365
+ gasLimit: o.callback.gasLimit
1366
+ },
1367
+ ...o.signature !== null && o.signature !== void 0 ? { signature: o.signature } : {}
1368
+ }),
1369
+ consumed: o.consumed,
1370
+ status: o.status,
1371
+ ...o.metadata ? { metadata: o.metadata } : {}
1372
+ }));
1328
1373
  return {
1329
- offers,
1374
+ offers: data,
1330
1375
  nextCursor
1331
1376
  };
1332
1377
  },
@@ -1433,7 +1478,6 @@ async function serve(parameters) {
1433
1478
  maxMaturity: params.max_maturity,
1434
1479
  loanToken: params.loan_token,
1435
1480
  creator: params.creator,
1436
- status: params.status,
1437
1481
  cursor: params.cursor,
1438
1482
  limit: params.limit
1439
1483
  });
@@ -1549,6 +1593,140 @@ function handleAPIError(error2, c) {
1549
1593
  });
1550
1594
  }
1551
1595
 
1596
+ // src/Liquidity.ts
1597
+ var Liquidity_exports = {};
1598
+ __export(Liquidity_exports, {
1599
+ fetch: () => fetch2,
1600
+ fetchBalancesAndAllowances: () => fetchBalancesAndAllowances,
1601
+ serialize: () => serialize
1602
+ });
1603
+ async function fetchBalancesAndAllowances(parameters) {
1604
+ const { client, spender, pairs, options } = parameters;
1605
+ if (pairs.length === 0) return /* @__PURE__ */ new Map();
1606
+ const batchSize = Math.max(1, options?.batchSize ?? 5e3);
1607
+ const retryAttempts = Math.max(1, options?.retryAttempts ?? 3);
1608
+ const retryDelayMs = Math.max(0, options?.retryDelayMs ?? 50);
1609
+ const blockNumber = options?.blockNumber ? BigInt(options.blockNumber) : void 0;
1610
+ const out = /* @__PURE__ */ new Map();
1611
+ for (const pairsBatch of Utils.batch(pairs, batchSize)) {
1612
+ const balanceContracts = [];
1613
+ const allowanceContracts = [];
1614
+ for (const { user, token } of pairsBatch) {
1615
+ balanceContracts.push({
1616
+ address: token,
1617
+ abi: erc20Abi,
1618
+ functionName: "balanceOf",
1619
+ args: [user]
1620
+ });
1621
+ allowanceContracts.push({
1622
+ address: token,
1623
+ abi: erc20Abi,
1624
+ functionName: "allowance",
1625
+ args: [user, spender]
1626
+ });
1627
+ }
1628
+ const [balances, allowances] = await Promise.all([
1629
+ Utils.retry(
1630
+ () => client.multicall({
1631
+ allowFailure: false,
1632
+ contracts: balanceContracts,
1633
+ ...blockNumber ? { blockNumber } : {}
1634
+ }),
1635
+ retryAttempts,
1636
+ retryDelayMs
1637
+ ),
1638
+ Utils.retry(
1639
+ () => client.multicall({
1640
+ allowFailure: false,
1641
+ contracts: allowanceContracts,
1642
+ ...blockNumber ? { blockNumber } : {}
1643
+ }),
1644
+ retryAttempts,
1645
+ retryDelayMs
1646
+ )
1647
+ ]);
1648
+ for (let i = 0; i < pairsBatch.length; i++) {
1649
+ const { user, token } = pairsBatch[i];
1650
+ const balance = balances[i];
1651
+ const allowance = allowances[i];
1652
+ let perUser = out.get(user);
1653
+ if (!perUser) {
1654
+ perUser = /* @__PURE__ */ new Map();
1655
+ out.set(user, perUser);
1656
+ }
1657
+ perUser.set(token, { balance, allowance });
1658
+ }
1659
+ }
1660
+ return out;
1661
+ }
1662
+ async function fetch2(parameters) {
1663
+ const { client, chainId, spender, type, pairs, options } = parameters;
1664
+ if (type !== "buy_with_empty_callback" /* BuyWithEmptyCallback */)
1665
+ throw new Error(`CallbackType not implemented: ${type}`);
1666
+ const map = await fetchBalancesAndAllowances({
1667
+ client,
1668
+ spender,
1669
+ pairs: pairs.map(({ user, contract }) => ({ user, token: contract })),
1670
+ options
1671
+ });
1672
+ const out = [];
1673
+ for (const [user, perContract] of map) {
1674
+ for (const [contract, { balance, allowance }] of perContract) {
1675
+ const amount = balance < allowance ? balance : allowance;
1676
+ out.push(
1677
+ buildLiquidity({
1678
+ type,
1679
+ user,
1680
+ contract,
1681
+ chainId,
1682
+ amount: amount.toString(),
1683
+ index: 0
1684
+ })
1685
+ );
1686
+ }
1687
+ }
1688
+ return out;
1689
+ }
1690
+ function serialize(liquidity) {
1691
+ const normalized = {
1692
+ userPosition: {
1693
+ id: liquidity.userPosition.id,
1694
+ availableLiquidityQueueId: liquidity.userPosition.availableLiquidityQueueId,
1695
+ user: liquidity.userPosition.user,
1696
+ chainId: String(liquidity.userPosition.chainId),
1697
+ amount: String(liquidity.userPosition.amount)
1698
+ },
1699
+ queues: liquidity.queues.map((queueWithPool) => ({
1700
+ queue: {
1701
+ queueId: queueWithPool.queue.queueId,
1702
+ availableLiquidityPoolId: queueWithPool.queue.availableLiquidityPoolId,
1703
+ index: queueWithPool.queue.index
1704
+ },
1705
+ pool: {
1706
+ id: queueWithPool.pool.id,
1707
+ amount: String(queueWithPool.pool.amount)
1708
+ }
1709
+ })).sort(
1710
+ (left, right) => {
1711
+ const leftQueueId = left.queue.queueId || "";
1712
+ const rightQueueId = right.queue.queueId || "";
1713
+ if (leftQueueId < rightQueueId) return -1;
1714
+ if (leftQueueId > rightQueueId) return 1;
1715
+ const leftPoolId = left.pool.id;
1716
+ const rightPoolId = right.pool.id;
1717
+ if (leftPoolId < rightPoolId) return -1;
1718
+ if (leftPoolId > rightPoolId) return 1;
1719
+ const leftIndex = left.queue.index;
1720
+ const rightIndex = right.queue.index;
1721
+ if (leftIndex < rightIndex) return -1;
1722
+ if (leftIndex > rightIndex) return 1;
1723
+ return 0;
1724
+ }
1725
+ )
1726
+ };
1727
+ return JSON.stringify(normalized);
1728
+ }
1729
+
1552
1730
  // src/Logger.ts
1553
1731
  var Logger_exports = {};
1554
1732
  __export(Logger_exports, {
@@ -1671,14 +1849,14 @@ async function run(parameters) {
1671
1849
  // src/ValidationRule.ts
1672
1850
  var ValidationRule_exports = {};
1673
1851
  __export(ValidationRule_exports, {
1674
- batch: () => batch2,
1852
+ batch: () => batch,
1675
1853
  morpho: () => morpho,
1676
1854
  single: () => single
1677
1855
  });
1678
1856
  function single(name, run2) {
1679
1857
  return { kind: "single", name, run: run2 };
1680
1858
  }
1681
- function batch2(name, run2) {
1859
+ function batch(name, run2) {
1682
1860
  return { kind: "batch", name, run: run2 };
1683
1861
  }
1684
1862
  function morpho() {
@@ -1719,6 +1897,6 @@ function morpho() {
1719
1897
  ];
1720
1898
  }
1721
1899
 
1722
- export { apiSchema_exports as ApiSchema, Logger_exports as Logger, OfferStore_exports as OfferStore, router_exports as Router, RouterOffer_exports as RouterOffer, utils_exports as Utils, Validation_exports as Validation, ValidationRule_exports as ValidationRule };
1900
+ export { apiSchema_exports as ApiSchema, Callback_exports as Callback, Cursor_exports as Cursor, Liquidity_exports as Liquidity, Logger_exports as Logger, OfferStore_exports as OfferStore, router_exports as Router, RouterOffer_exports as RouterOffer, Validation_exports as Validation, ValidationRule_exports as ValidationRule };
1723
1901
  //# sourceMappingURL=index.node.mjs.map
1724
1902
  //# sourceMappingURL=index.node.mjs.map