@morpho-dev/router 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +67 -71
  2. package/dist/cli.js +4224 -1627
  3. package/dist/drizzle/migrations/0015_add-lots-table.sql +12 -0
  4. package/dist/drizzle/migrations/0016_merkle-metadata.sql +26 -0
  5. package/dist/drizzle/migrations/0017_dusty_the_hunter.sql +1 -0
  6. package/dist/drizzle/migrations/0018_add_chain_collector_constraints.sql +3 -0
  7. package/dist/drizzle/migrations/0019_add-obligation-units-shares.sql +2 -0
  8. package/dist/drizzle/migrations/0020_add-session.sql +1 -0
  9. package/dist/drizzle/migrations/0021_drop_chain_collector_epoch_indexes.sql +2 -0
  10. package/dist/drizzle/migrations/0021_migrate-rate-to-price.sql +15 -0
  11. package/dist/drizzle/migrations/0022_consolidate-price.sql +15 -0
  12. package/dist/drizzle/migrations/meta/0015_snapshot.json +1365 -0
  13. package/dist/drizzle/migrations/meta/0016_snapshot.json +1531 -0
  14. package/dist/drizzle/migrations/meta/0017_snapshot.json +1525 -0
  15. package/dist/drizzle/migrations/meta/0018_snapshot.json +1572 -0
  16. package/dist/drizzle/migrations/meta/0019_snapshot.json +1586 -0
  17. package/dist/drizzle/migrations/meta/_journal.json +56 -0
  18. package/dist/evm/bytecode/erc20.txt +1 -0
  19. package/dist/evm/bytecode/factory.txt +1 -0
  20. package/dist/evm/bytecode/mempool.txt +1 -0
  21. package/dist/evm/bytecode/morpho.txt +1 -0
  22. package/dist/evm/bytecode/multicall3.txt +1 -0
  23. package/dist/evm/bytecode/oracle.txt +1 -0
  24. package/dist/evm/bytecode/terms.txt +1 -0
  25. package/dist/evm/bytecode/vault.txt +1 -0
  26. package/dist/evm/bytecode/vaultV1.txt +1 -0
  27. package/dist/index.browser.d.mts +1376 -651
  28. package/dist/index.browser.d.mts.map +1 -1
  29. package/dist/index.browser.d.ts +1375 -654
  30. package/dist/index.browser.d.ts.map +1 -1
  31. package/dist/index.browser.js +2398 -1526
  32. package/dist/index.browser.js.map +1 -1
  33. package/dist/index.browser.mjs +2394 -1522
  34. package/dist/index.browser.mjs.map +1 -1
  35. package/dist/index.node.d.mts +2372 -1039
  36. package/dist/index.node.d.mts.map +1 -1
  37. package/dist/index.node.d.ts +2372 -1039
  38. package/dist/index.node.d.ts.map +1 -1
  39. package/dist/index.node.js +3094 -1399
  40. package/dist/index.node.js.map +1 -1
  41. package/dist/index.node.mjs +3075 -1399
  42. package/dist/index.node.mjs.map +1 -1
  43. package/docs/integrator.md +78 -0
  44. package/package.json +11 -6
@@ -1,23 +1,21 @@
1
1
  import { t as __export } from "./chunk-jass6xSI.mjs";
2
2
  import { z } from "zod/v4";
3
- import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, parseAbi, publicActions, zeroAddress } from "viem";
4
- import "reflect-metadata";
5
- import { generateDocument } from "openapi-metadata";
6
- import { ApiBody, ApiOperation, ApiProperty, ApiQuery, ApiResponse, ApiTags } from "openapi-metadata/decorators";
7
- import * as z$1 from "zod";
8
- import { Base64 } from "js-base64";
9
- import createOpenApiFetchClient from "openapi-fetch";
3
+ import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashMessage, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, publicActions, recoverAddress, zeroAddress } from "viem";
10
4
  import { getBlock, getLogs, multicall } from "viem/actions";
11
5
  import { anvil, base, mainnet } from "viem/chains";
12
- import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
6
+ import * as z$1 from "zod";
13
7
  import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
14
8
  import { gzip, ungzip } from "pako";
9
+ import "reflect-metadata";
10
+ import { generateDocument } from "openapi-metadata";
11
+ import { ApiBody, ApiOperation, ApiParam, ApiProperty, ApiQuery, ApiResponse, ApiTags } from "openapi-metadata/decorators";
12
+ import createOpenApiFetchClient from "openapi-fetch";
15
13
 
16
14
  //#region src/api/Schema/BookResponse.ts
17
- var BookResponse_exports = /* @__PURE__ */ __export({ from: () => from$13 });
18
- function from$13(level) {
15
+ var BookResponse_exports = /* @__PURE__ */ __export({ from: () => from$14 });
16
+ function from$14(level) {
19
17
  return {
20
- rate: level.rate.toString(),
18
+ price: level.price.toString(),
21
19
  assets: level.assets.toString(),
22
20
  count: level.count
23
21
  };
@@ -35,1041 +33,127 @@ const CollectorHealth = z.object({
35
33
  "live",
36
34
  "lagging",
37
35
  "unknown"
38
- ])
36
+ ]),
37
+ initialized: z.boolean()
39
38
  });
40
39
  const CollectorsHealthResponse = z.array(CollectorHealth);
41
40
  const ChainHealth = z.object({
42
41
  chain_id: z.number(),
43
- local_block_number: z.number(),
42
+ local_block_number: z.number().nullable(),
44
43
  remote_block_number: z.number().nullable(),
45
- updated_at: z.string()
44
+ updated_at: z.string().nullable(),
45
+ initialized: z.boolean()
46
46
  });
47
47
  const ChainsHealthResponse = z.array(ChainHealth);
48
- const RouterStatusResponse = z.object({ status: z.enum(["live", "syncing"]) });
49
-
50
- //#endregion
51
- //#region src/utils/Format.ts
52
- var Format_exports = /* @__PURE__ */ __export({
53
- fromSnakeCase: () => fromSnakeCase$3,
54
- stringifyBigint: () => stringifyBigint,
55
- toSnakeCase: () => toSnakeCase$1
48
+ const RouterStatusResponse = z.object({
49
+ status: z.enum(["live", "syncing"]),
50
+ initialized: z.boolean(),
51
+ missing_chains: z.array(z.number()),
52
+ missing_collectors: z.array(z.object({
53
+ chain_id: z.number(),
54
+ name: z.string()
55
+ }))
56
56
  });
57
- /**
58
- * Formats object keys to snake case.
59
- * Preserves ethereum addresses as is.
60
- * Converts ethereum addresses to checksummed if used as values.
61
- * Stringifies bigint values to strings.
62
- */
63
- function toSnakeCase$1(obj) {
64
- return stringifyBigint(processObject(obj, (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`), (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? getAddress(value.toLowerCase()) : value));
65
- }
66
- /**
67
- * Formats a snake case object to its camel case type.
68
- * Preserves ethereum addresses as is.
69
- * Converts checksummed ethereum addresses to lowercase if used as values.
70
- * @warning Does not unstringify bigint values.
71
- */
72
- function fromSnakeCase$3(obj) {
73
- return processObject(obj, (s) => isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()), (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value);
74
- }
75
- function processObject(obj, fnKey, fnValue) {
76
- if (typeof obj !== "object" || obj === null) return obj;
77
- if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
78
- return Object.entries(obj).reduce((acc, [key, value]) => {
79
- const newKey = fnKey(key);
80
- acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
81
- return acc;
82
- }, {});
83
- }
84
- function stringifyBigint(value) {
85
- if (typeof value === "bigint") return value.toString();
86
- if (Array.isArray(value)) return value.map(stringifyBigint);
87
- if (value && typeof value === "object") {
88
- const out = {};
89
- for (const [k, v] of Object.entries(value)) out[k] = stringifyBigint(v);
90
- return out;
91
- }
92
- return value;
93
- }
94
57
 
95
58
  //#endregion
96
59
  //#region src/api/Schema/ObligationResponse.ts
97
- var ObligationResponse_exports = /* @__PURE__ */ __export({ from: () => from$12 });
60
+ var ObligationResponse_exports = /* @__PURE__ */ __export({ from: () => from$13 });
98
61
  /**
99
62
  * Creates an `ObligationResponse` from a `Obligation`.
100
63
  * @constructor
101
64
  * @param obligation - {@link Obligation}
102
65
  * @returns The created `ObligationResponse`. {@link ObligationResponse}
103
66
  */
104
- function from$12(obligation, quote) {
105
- return toSnakeCase$1({
106
- id: quote.obligationId,
107
- ...obligation,
108
- ask: quote.ask,
109
- bid: quote.bid
110
- });
111
- }
112
-
113
- //#endregion
114
- //#region src/api/Schema/OfferResponse.ts
115
- var OfferResponse_exports = /* @__PURE__ */ __export({ from: () => from$11 });
116
- /**
117
- * Creates an `OfferResponse` from an `Offer`.
118
- * @constructor
119
- * @param offer - {@link Offer}
120
- * @returns The created `OfferResponse`. {@link OfferResponse}
121
- */
122
- function from$11(offer) {
123
- const result = toSnakeCase$1(offer);
67
+ function from$13(obligation, quote) {
124
68
  return {
125
- ...result,
126
- signature: result.signature ?? null
69
+ id: quote.obligationId,
70
+ chain_id: obligation.chainId,
71
+ loan_token: obligation.loanToken,
72
+ collaterals: obligation.collaterals.map((c) => ({
73
+ token: c.asset,
74
+ lltv: c.lltv.toString(),
75
+ oracle: c.oracle
76
+ })),
77
+ maturity: obligation.maturity,
78
+ ask: { price: quote.ask.price.toString() },
79
+ bid: { price: quote.bid.price.toString() }
127
80
  };
128
81
  }
129
82
 
130
83
  //#endregion
131
- //#region src/api/Controllers/Payload.ts
132
- const API_ERROR_CODES = [
133
- "VALIDATION_ERROR",
134
- "NOT_FOUND",
135
- "INTERNAL_SERVER_ERROR",
136
- "BAD_REQUEST"
137
- ];
84
+ //#region src/core/Abi/MetaMorpho.ts
85
+ const MetaMorpho = parseAbi([
86
+ "function balanceOf(address account) view returns (uint256)",
87
+ "function DECIMALS_OFFSET() view returns (uint8)",
88
+ "function totalAssets() view returns (uint256)",
89
+ "function totalSupply() view returns (uint256)",
90
+ "function maxWithdraw(address owner) view returns (uint256 assets)",
91
+ "function asset() view returns (address)",
92
+ "event Transfer(address indexed from, address indexed to, uint256 value)",
93
+ "function withdrawQueue(uint256 index) view returns (bytes32)",
94
+ "function withdrawQueueLength() view returns (uint256)"
95
+ ]);
138
96
 
139
97
  //#endregion
140
- //#region \0@oxc-project+runtime@0.97.0/helpers/decorate.js
141
- function __decorate(decorators, target, key, desc) {
142
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
143
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
144
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
145
- return c > 3 && r && Object.defineProperty(target, key, r), r;
146
- }
98
+ //#region src/core/Abi/MetaMorphoFactory.ts
99
+ const MetaMorphoFactory = parseAbi(["event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)", "function isMetaMorpho(address) view returns (bool)"]);
147
100
 
148
101
  //#endregion
149
- //#region src/api/Schema/openapi.ts
150
- const timestampExample = "2024-01-01T12:00:00.000Z";
151
- const offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
152
- const obligationCursorExample = "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc";
153
- const offerExample = {
154
- hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
155
- offering: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
156
- assets: "369216000000000000000000",
157
- rate: "2750000000000000000",
158
- maturity: 1761922799,
159
- expiry: 1761922799,
160
- start: 1761922790,
161
- nonce: "571380",
162
- buy: false,
163
- chain_id: 1,
164
- loan_token: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
165
- collaterals: [{
166
- asset: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
167
- oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401",
168
- lltv: "860000000000000000"
102
+ //#region src/core/Abi/index.ts
103
+ var Abi_exports = /* @__PURE__ */ __export({
104
+ ERC4626: () => ERC4626,
105
+ MetaMorpho: () => MetaMorpho,
106
+ MetaMorphoFactory: () => MetaMorphoFactory,
107
+ Morpho: () => Morpho,
108
+ Oracle: () => Oracle
109
+ });
110
+ const Oracle = [{
111
+ type: "function",
112
+ name: "price",
113
+ inputs: [],
114
+ outputs: [{
115
+ name: "",
116
+ type: "uint256"
169
117
  }],
170
- callback: {
171
- address: "0x1111111111111111111111111111111111111111",
172
- data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000",
173
- gas_limit: "500000"
174
- },
175
- signature: "0x1234567890123456789012345678901234567890123456789012345678901234123456789012345678901234567890123456789012345678901234567890123400",
176
- consumed: "0",
177
- takeable: "369216000000000000000000",
178
- block_number: 0xa7495128adfb1
179
- };
180
- const collectorsHealthExample = {
181
- name: "offers",
182
- chain_id: 1,
183
- block_number: 21345678,
184
- updated_at: timestampExample,
185
- lag: 0,
186
- status: "live"
187
- };
188
- const chainsHealthExample = {
189
- chain_id: 1,
190
- local_block_number: 21345678,
191
- remote_block_number: 21345690,
192
- updated_at: timestampExample
193
- };
194
- const routerStatusExample = { status: "live" };
195
- var Meta = class {};
196
- __decorate([ApiProperty({
197
- type: "string",
198
- example: timestampExample
199
- })], Meta.prototype, "timestamp", void 0);
200
- var SuccessResponse = class {};
201
- __decorate([ApiProperty({ type: () => Meta })], SuccessResponse.prototype, "meta", void 0);
202
- var ErrorResponse = class {};
203
- __decorate([ApiProperty({
204
- type: "string",
205
- enum: API_ERROR_CODES,
206
- example: "VALIDATION_ERROR"
207
- })], ErrorResponse.prototype, "code", void 0);
208
- __decorate([ApiProperty({
209
- type: "string",
210
- example: "Limit must be greater than 0."
211
- })], ErrorResponse.prototype, "message", void 0);
212
- __decorate([ApiProperty({
213
- type: "object",
214
- example: [{
215
- field: "limit",
216
- issue: "Limit must be greater than 0."
217
- }]
218
- })], ErrorResponse.prototype, "details", void 0);
219
- var BadRequestResponse = class {};
220
- __decorate([ApiProperty({ type: () => ErrorResponse })], BadRequestResponse.prototype, "error", void 0);
221
- __decorate([ApiProperty({ type: () => Meta })], BadRequestResponse.prototype, "meta", void 0);
222
- var CollateralResponse = class {};
223
- __decorate([ApiProperty({
224
- type: "string",
225
- example: "0x34Cf890dB685FC536E05652FB41f02090c3fb751"
226
- })], CollateralResponse.prototype, "asset", void 0);
227
- __decorate([ApiProperty({
228
- type: "string",
229
- example: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
230
- })], CollateralResponse.prototype, "oracle", void 0);
231
- __decorate([ApiProperty({
232
- type: "string",
233
- example: "860000000000000000"
234
- })], CollateralResponse.prototype, "lltv", void 0);
235
- var AskResponse = class {};
236
- __decorate([ApiProperty({
237
- type: "string",
238
- example: "1000000000000000000"
239
- })], AskResponse.prototype, "rate", void 0);
240
- var BidResponse = class {};
241
- __decorate([ApiProperty({
242
- type: "string",
243
- example: "1000000000000000000"
244
- })], BidResponse.prototype, "rate", void 0);
245
- var OfferCallbackResponse = class {};
246
- __decorate([ApiProperty({
247
- type: "string",
248
- example: offerExample.callback.address
249
- })], OfferCallbackResponse.prototype, "address", void 0);
250
- __decorate([ApiProperty({
251
- type: "string",
252
- example: offerExample.callback.data
253
- })], OfferCallbackResponse.prototype, "data", void 0);
254
- __decorate([ApiProperty({
255
- type: "string",
256
- example: offerExample.callback.gas_limit
257
- })], OfferCallbackResponse.prototype, "gas_limit", void 0);
258
- var OfferListItemResponse = class {};
259
- __decorate([ApiProperty({
260
- type: "string",
261
- example: offerExample.hash
262
- })], OfferListItemResponse.prototype, "hash", void 0);
263
- __decorate([ApiProperty({
264
- type: "string",
265
- example: offerExample.offering
266
- })], OfferListItemResponse.prototype, "offering", void 0);
267
- __decorate([ApiProperty({
268
- type: "string",
269
- example: offerExample.assets
270
- })], OfferListItemResponse.prototype, "assets", void 0);
271
- __decorate([ApiProperty({
272
- type: "string",
273
- example: offerExample.rate
274
- })], OfferListItemResponse.prototype, "rate", void 0);
275
- __decorate([ApiProperty({
276
- type: "number",
277
- example: offerExample.maturity
278
- })], OfferListItemResponse.prototype, "maturity", void 0);
279
- __decorate([ApiProperty({
280
- type: "number",
281
- example: offerExample.expiry
282
- })], OfferListItemResponse.prototype, "expiry", void 0);
283
- __decorate([ApiProperty({
284
- type: "number",
285
- example: offerExample.start
286
- })], OfferListItemResponse.prototype, "start", void 0);
287
- __decorate([ApiProperty({
288
- type: "string",
289
- example: offerExample.nonce
290
- })], OfferListItemResponse.prototype, "nonce", void 0);
291
- __decorate([ApiProperty({
292
- type: "boolean",
293
- example: offerExample.buy
294
- })], OfferListItemResponse.prototype, "buy", void 0);
295
- __decorate([ApiProperty({
296
- type: "number",
297
- example: offerExample.chain_id
298
- })], OfferListItemResponse.prototype, "chain_id", void 0);
299
- __decorate([ApiProperty({
300
- type: "string",
301
- example: offerExample.loan_token
302
- })], OfferListItemResponse.prototype, "loan_token", void 0);
303
- __decorate([ApiProperty({
304
- type: () => [CollateralResponse],
305
- example: offerExample.collaterals
306
- })], OfferListItemResponse.prototype, "collaterals", void 0);
307
- __decorate([ApiProperty({
308
- type: () => OfferCallbackResponse,
309
- example: offerExample.callback
310
- })], OfferListItemResponse.prototype, "callback", void 0);
311
- __decorate([ApiProperty({
312
- type: "string",
313
- example: offerExample.takeable
314
- })], OfferListItemResponse.prototype, "takeable", void 0);
315
- __decorate([ApiProperty({
316
- type: "string",
317
- example: offerExample.consumed
318
- })], OfferListItemResponse.prototype, "consumed", void 0);
319
- __decorate([ApiProperty({
320
- type: "number",
321
- example: offerExample.block_number
322
- })], OfferListItemResponse.prototype, "block_number", void 0);
323
- __decorate([ApiProperty({
324
- type: "string",
325
- nullable: true,
326
- example: offerExample.signature
327
- })], OfferListItemResponse.prototype, "signature", void 0);
328
- var ObligationResponse = class {};
329
- __decorate([ApiProperty({
330
- type: "string",
331
- example: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67"
332
- })], ObligationResponse.prototype, "id", void 0);
333
- __decorate([ApiProperty({
334
- type: "number",
335
- example: 1
336
- })], ObligationResponse.prototype, "chain_id", void 0);
337
- __decorate([ApiProperty({
338
- type: "string",
339
- example: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078"
340
- })], ObligationResponse.prototype, "loan_token", void 0);
341
- __decorate([ApiProperty({ type: () => [CollateralResponse] })], ObligationResponse.prototype, "collaterals", void 0);
342
- __decorate([ApiProperty({
343
- type: "number",
344
- example: 1761922800
345
- })], ObligationResponse.prototype, "maturity", void 0);
346
- __decorate([ApiProperty({ type: () => AskResponse })], ObligationResponse.prototype, "ask", void 0);
347
- __decorate([ApiProperty({ type: () => BidResponse })], ObligationResponse.prototype, "bid", void 0);
348
- var ObligationListResponse = class extends SuccessResponse {};
349
- __decorate([ApiProperty({
350
- type: "string",
351
- nullable: true,
352
- example: obligationCursorExample
353
- })], ObligationListResponse.prototype, "cursor", void 0);
354
- __decorate([ApiProperty({
355
- type: () => [ObligationResponse],
356
- description: "List of obligations with takable offers."
357
- })], ObligationListResponse.prototype, "data", void 0);
358
- var ObligationSingleSuccessResponse = class extends SuccessResponse {};
359
- __decorate([ApiProperty({
360
- type: "string",
361
- nullable: true,
362
- example: null
363
- })], ObligationSingleSuccessResponse.prototype, "cursor", void 0);
364
- __decorate([ApiProperty({
365
- type: () => ObligationResponse,
366
- description: "Obligation details."
367
- })], ObligationSingleSuccessResponse.prototype, "data", void 0);
368
- var OfferListResponse = class extends SuccessResponse {};
369
- __decorate([ApiProperty({
370
- type: "string",
371
- nullable: true,
372
- example: offerCursorExample
373
- })], OfferListResponse.prototype, "cursor", void 0);
374
- __decorate([ApiProperty({
375
- type: () => [OfferListItemResponse],
376
- description: "Offers matching the provided filters.",
377
- example: [offerExample]
378
- })], OfferListResponse.prototype, "data", void 0);
379
- var RouterStatusDataResponse = class {};
380
- __decorate([ApiProperty({
381
- type: "string",
382
- enum: ["live", "syncing"],
383
- example: routerStatusExample.status
384
- })], RouterStatusDataResponse.prototype, "status", void 0);
385
- var RouterStatusSuccessResponse = class extends SuccessResponse {};
386
- __decorate([ApiProperty({
387
- type: () => RouterStatusDataResponse,
388
- description: "Aggregated router status.",
389
- example: routerStatusExample
390
- })], RouterStatusSuccessResponse.prototype, "data", void 0);
391
- var CollectorHealthResponse = class {};
392
- __decorate([ApiProperty({
393
- type: "string",
394
- example: collectorsHealthExample.name
395
- })], CollectorHealthResponse.prototype, "name", void 0);
396
- __decorate([ApiProperty({
397
- type: "number",
398
- example: collectorsHealthExample.chain_id
399
- })], CollectorHealthResponse.prototype, "chain_id", void 0);
400
- __decorate([ApiProperty({
401
- type: "number",
402
- nullable: true,
403
- example: collectorsHealthExample.block_number
404
- })], CollectorHealthResponse.prototype, "block_number", void 0);
405
- __decorate([ApiProperty({
406
- type: "string",
407
- nullable: true,
408
- example: collectorsHealthExample.updated_at
409
- })], CollectorHealthResponse.prototype, "updated_at", void 0);
410
- __decorate([ApiProperty({
411
- type: "number",
412
- nullable: true,
413
- example: collectorsHealthExample.lag
414
- })], CollectorHealthResponse.prototype, "lag", void 0);
415
- __decorate([ApiProperty({
416
- type: "string",
417
- enum: [
418
- "live",
419
- "lagging",
420
- "unknown"
421
- ],
422
- example: collectorsHealthExample.status
423
- })], CollectorHealthResponse.prototype, "status", void 0);
424
- var CollectorsHealthSuccessResponse = class extends SuccessResponse {};
425
- __decorate([ApiProperty({
426
- type: () => [CollectorHealthResponse],
427
- description: "Collectors health details and sync status.",
428
- example: [collectorsHealthExample]
429
- })], CollectorsHealthSuccessResponse.prototype, "data", void 0);
430
- var ChainHealthResponse = class {};
431
- __decorate([ApiProperty({
432
- type: "number",
433
- example: chainsHealthExample.chain_id
434
- })], ChainHealthResponse.prototype, "chain_id", void 0);
435
- __decorate([ApiProperty({
436
- type: "number",
437
- example: chainsHealthExample.local_block_number
438
- })], ChainHealthResponse.prototype, "local_block_number", void 0);
439
- __decorate([ApiProperty({
440
- type: "number",
441
- nullable: true,
442
- example: chainsHealthExample.remote_block_number
443
- })], ChainHealthResponse.prototype, "remote_block_number", void 0);
444
- __decorate([ApiProperty({
445
- type: "string",
446
- example: chainsHealthExample.updated_at
447
- })], ChainHealthResponse.prototype, "updated_at", void 0);
448
- var ChainsHealthSuccessResponse = class extends SuccessResponse {};
449
- __decorate([ApiProperty({
450
- type: () => [ChainHealthResponse],
451
- description: "Latest processed block per chain.",
452
- example: [chainsHealthExample]
453
- })], ChainsHealthSuccessResponse.prototype, "data", void 0);
454
- var ValidateOfferRequest = class {};
455
- __decorate([ApiProperty({
456
- type: "string",
457
- example: offerExample.offering
458
- })], ValidateOfferRequest.prototype, "offering", void 0);
459
- __decorate([ApiProperty({
460
- type: "string",
461
- example: offerExample.assets
462
- })], ValidateOfferRequest.prototype, "assets", void 0);
463
- __decorate([ApiProperty({
464
- type: "string",
465
- example: offerExample.rate
466
- })], ValidateOfferRequest.prototype, "rate", void 0);
467
- __decorate([ApiProperty({
468
- type: "number",
469
- example: offerExample.maturity
470
- })], ValidateOfferRequest.prototype, "maturity", void 0);
471
- __decorate([ApiProperty({
472
- type: "number",
473
- example: offerExample.expiry
474
- })], ValidateOfferRequest.prototype, "expiry", void 0);
475
- __decorate([ApiProperty({
476
- type: "number",
477
- example: offerExample.start
478
- })], ValidateOfferRequest.prototype, "start", void 0);
479
- __decorate([ApiProperty({
480
- type: "string",
481
- example: offerExample.nonce
482
- })], ValidateOfferRequest.prototype, "nonce", void 0);
483
- __decorate([ApiProperty({
484
- type: "boolean",
485
- example: offerExample.buy
486
- })], ValidateOfferRequest.prototype, "buy", void 0);
487
- __decorate([ApiProperty({
488
- type: "number",
489
- example: offerExample.chain_id
490
- })], ValidateOfferRequest.prototype, "chain_id", void 0);
491
- __decorate([ApiProperty({
492
- type: "string",
493
- example: offerExample.loan_token
494
- })], ValidateOfferRequest.prototype, "loan_token", void 0);
495
- __decorate([ApiProperty({
496
- type: () => [CollateralResponse],
497
- example: offerExample.collaterals
498
- })], ValidateOfferRequest.prototype, "collaterals", void 0);
499
- __decorate([ApiProperty({
500
- type: () => OfferCallbackResponse,
501
- example: offerExample.callback
502
- })], ValidateOfferRequest.prototype, "callback", void 0);
503
- var ValidateOffersRequest = class {};
504
- __decorate([ApiProperty({
505
- type: () => [ValidateOfferRequest],
506
- description: "Array of offers in snake_case format. Mutually exclusive with 'calldata'.",
507
- required: false
508
- })], ValidateOffersRequest.prototype, "offers", void 0);
509
- __decorate([ApiProperty({
510
- type: "string",
511
- description: "Encoded tree calldata as a hex string (0x-prefixed). Mutually exclusive with 'offers'.",
512
- example: "0x01...",
513
- required: false
514
- })], ValidateOffersRequest.prototype, "calldata", void 0);
515
- var ValidateOfferResultResponse = class {};
516
- __decorate([ApiProperty({
517
- type: "string",
518
- example: offerExample.hash
519
- })], ValidateOfferResultResponse.prototype, "offer_hash", void 0);
520
- __decorate([ApiProperty({
521
- type: "boolean",
522
- example: false
523
- })], ValidateOfferResultResponse.prototype, "valid", void 0);
524
- __decorate([ApiProperty({
525
- type: "string",
526
- example: "parse_error",
527
- nullable: true
528
- })], ValidateOfferResultResponse.prototype, "rule", void 0);
529
- __decorate([ApiProperty({
530
- type: "string",
531
- example: "Invalid offer. 'offering': invalid address",
532
- nullable: true
533
- })], ValidateOfferResultResponse.prototype, "message", void 0);
534
- var ValidateOffersListResponse = class extends SuccessResponse {};
535
- __decorate([ApiProperty({
536
- type: "string",
537
- nullable: true,
538
- example: null
539
- })], ValidateOffersListResponse.prototype, "cursor", void 0);
540
- __decorate([ApiProperty({
541
- type: () => [ValidateOfferResultResponse],
542
- description: "Validation results for each offer."
543
- })], ValidateOffersListResponse.prototype, "data", void 0);
544
- var BookLevelResponse = class {};
545
- __decorate([ApiProperty({
546
- type: "string",
547
- example: "2750000000000000000"
548
- })], BookLevelResponse.prototype, "rate", void 0);
549
- __decorate([ApiProperty({
550
- type: "string",
551
- example: "369216000000000000000000"
552
- })], BookLevelResponse.prototype, "assets", void 0);
553
- __decorate([ApiProperty({
554
- type: "number",
555
- example: 5
556
- })], BookLevelResponse.prototype, "count", void 0);
557
- var BookListResponse = class extends SuccessResponse {};
558
- __decorate([ApiProperty({
559
- type: "string",
560
- nullable: true,
561
- example: offerCursorExample
562
- })], BookListResponse.prototype, "cursor", void 0);
563
- __decorate([ApiProperty({
564
- type: () => [BookLevelResponse],
565
- description: "Aggregated book levels grouped by rate."
566
- })], BookListResponse.prototype, "data", void 0);
567
- let BooksController = class BooksController$1 {
568
- async getBook() {}
569
- };
570
- __decorate([
571
- ApiOperation({
572
- methods: ["get"],
573
- path: "/v1/books/{obligationId}/{side}",
574
- summary: "Get aggregated book",
575
- description: "Returns aggregated book data for a given obligation and side. Offers are grouped by rate with summed takeable amounts. Book levels are sorted by rate (ascending for buy side, descending for sell side)."
576
- }),
577
- ApiQuery({
578
- name: "cursor",
579
- type: "string",
580
- example: offerCursorExample,
581
- description: "Pagination cursor in base64url-encoded format."
582
- }),
583
- ApiQuery({
584
- name: "limit",
585
- type: "number",
586
- example: 10,
587
- description: "Maximum number of rate levels to return."
588
- }),
589
- ApiResponse({
590
- status: 200,
591
- description: "Success",
592
- type: BookListResponse
593
- })
594
- ], BooksController.prototype, "getBook", null);
595
- BooksController = __decorate([ApiTags("Books"), ApiResponse({
596
- status: 400,
597
- description: "Bad Request",
598
- type: BadRequestResponse
599
- })], BooksController);
600
- let ValidateController = class ValidateController$1 {
601
- async validateOffers() {}
602
- };
603
- __decorate([
604
- ApiOperation({
605
- methods: ["post"],
606
- path: "/v1/validate",
607
- summary: "Validate offers",
608
- description: "Validates offers against router validation rules. Returns validation status for each offer. Accepts either an array of offers or encoded calldata (mutually exclusive)."
609
- }),
610
- ApiBody({ type: ValidateOffersRequest }),
611
- ApiResponse({
612
- status: 200,
613
- description: "Success",
614
- type: ValidateOffersListResponse
615
- })
616
- ], ValidateController.prototype, "validateOffers", null);
617
- ValidateController = __decorate([ApiTags("Validate"), ApiResponse({
618
- status: 400,
619
- description: "Bad Request",
620
- type: BadRequestResponse
621
- })], ValidateController);
622
- let OffersController = class OffersController$1 {
623
- async getOffers() {}
624
- };
625
- __decorate([
626
- ApiOperation({
627
- methods: ["get"],
628
- path: "/v1/offers",
629
- summary: "List all offers",
630
- description: "Returns offers. Provide either `obligation_id` + `side` (order book) or `offering` (by maker)."
631
- }),
632
- ApiQuery({
633
- name: "side",
634
- type: "string",
635
- required: false,
636
- enum: ["buy", "sell"],
637
- example: "buy",
638
- description: "Side of the offer. Required when using obligation_id."
639
- }),
640
- ApiQuery({
641
- name: "obligation_id",
642
- type: "string",
643
- required: false,
644
- example: "0x1234567890123456789012345678901234567890123456789012345678901234",
645
- description: "Obligation id used to filter offers. Required when not using offering."
646
- }),
647
- ApiQuery({
648
- name: "offering",
649
- type: "string",
650
- required: false,
651
- example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
652
- description: "Maker address to filter offers by. Alternative to obligation_id + side."
653
- }),
654
- ApiQuery({
655
- name: "cursor",
656
- type: "string",
657
- example: offerCursorExample,
658
- description: "Pagination cursor in base64url-encoded format."
659
- }),
660
- ApiQuery({
661
- name: "limit",
662
- type: "number",
663
- example: 10,
664
- description: "Maximum number of offers to return."
665
- }),
666
- ApiResponse({
667
- status: 200,
668
- description: "Success",
669
- type: OfferListResponse
670
- })
671
- ], OffersController.prototype, "getOffers", null);
672
- OffersController = __decorate([ApiTags("Offers"), ApiResponse({
673
- status: 400,
674
- description: "Bad Request",
675
- type: BadRequestResponse
676
- })], OffersController);
677
- let HealthController = class HealthController$1 {
678
- async getRouterStatus() {}
679
- async getCollectorsHealth() {}
680
- async getChainsHealth() {}
681
- };
682
- __decorate([ApiOperation({
683
- methods: ["get"],
684
- path: "/v1/health",
685
- summary: "Retrieve global health",
686
- description: "Returns the aggregated status of the router."
687
- }), ApiResponse({
688
- status: 200,
689
- description: "Success",
690
- type: RouterStatusSuccessResponse
691
- })], HealthController.prototype, "getRouterStatus", null);
692
- __decorate([ApiOperation({
693
- methods: ["get"],
694
- path: "/v1/health/collectors",
695
- summary: "Retrieve collectors health",
696
- description: "Returns the latest block numbers processed by collectors and their sync status."
697
- }), ApiResponse({
698
- status: 200,
699
- description: "Success",
700
- type: CollectorsHealthSuccessResponse
701
- })], HealthController.prototype, "getCollectorsHealth", null);
702
- __decorate([ApiOperation({
703
- methods: ["get"],
704
- path: "/v1/health/chains",
705
- summary: "Retrieve chains health",
706
- description: "Returns the latest block that can be processed by collectors for each chain."
707
- }), ApiResponse({
708
- status: 200,
709
- description: "Success",
710
- type: ChainsHealthSuccessResponse
711
- })], HealthController.prototype, "getChainsHealth", null);
712
- HealthController = __decorate([ApiTags("Health")], HealthController);
713
- let ObligationsController = class ObligationsController$1 {
714
- async getObligations() {}
715
- async getObligation() {}
716
- };
717
- __decorate([
718
- ApiOperation({
719
- methods: ["get"],
720
- path: "/v1/obligations",
721
- summary: "List all obligations",
722
- description: "Returns a list of obligations with their current best ask and bid. Obligations are sorted by their id in ascending order by default."
723
- }),
724
- ApiQuery({
725
- name: "cursor",
726
- type: "string",
727
- example: obligationCursorExample
728
- }),
729
- ApiQuery({
730
- name: "limit",
731
- type: "number",
732
- example: 10
733
- }),
734
- ApiResponse({
735
- status: 200,
736
- description: "Success",
737
- type: ObligationListResponse
738
- })
739
- ], ObligationsController.prototype, "getObligations", null);
740
- __decorate([ApiOperation({
741
- methods: ["get"],
742
- path: "/v1/obligations/{obligationId}",
743
- summary: "Get an obligation",
744
- description: "Returns an obligation by its id."
745
- }), ApiResponse({
746
- status: 200,
747
- description: "Success",
748
- type: ObligationSingleSuccessResponse
749
- })], ObligationsController.prototype, "getObligation", null);
750
- ObligationsController = __decorate([ApiTags("Obligations"), ApiResponse({
751
- status: 400,
752
- description: "Bad Request",
753
- type: BadRequestResponse
754
- })], ObligationsController);
755
- const OpenApi = async (options = {}) => {
756
- const document = await generateDocument({
757
- controllers: [
758
- BooksController,
759
- OffersController,
760
- ObligationsController,
761
- HealthController,
762
- ValidateController
763
- ],
764
- document: {
765
- openapi: "3.1.0",
766
- info: {
767
- title: "Router API",
768
- version: "1.0.0",
769
- description: "API for the Morpho Router"
770
- },
771
- servers: [{
772
- url: "https://router.morpho.dev",
773
- description: "Production server"
774
- }, {
775
- url: "http://localhost:7891",
776
- description: "Local development server"
777
- }]
778
- }
779
- });
780
- if (options.rules && options.rules.length > 0) {
781
- const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
782
- const validatePath = document.paths?.["/v1/validate"];
783
- if (validatePath && "post" in validatePath && validatePath.post) validatePath.post.description = `Validates offers against router validation rules. Returns validation status for each offer.\n\n**Available validation rules:**\n${rulesDescription}`;
784
- }
785
- return document;
786
- };
787
-
788
- //#endregion
789
- //#region src/database/utils/Cursor.ts
790
- var Cursor_exports = /* @__PURE__ */ __export({
791
- decode: () => decode$3,
792
- encode: () => encode$3,
793
- validate: () => validate
794
- });
795
- function validate(cursor) {
796
- if (!cursor || typeof cursor !== "object") throw new Error("Cursor must be an object");
797
- const c = cursor;
798
- if (![
799
- "rate",
800
- "maturity",
801
- "expiry",
802
- "amount"
803
- ].includes(c.sort)) throw new Error(`Invalid sort field: ${c.sort}. Must be one of: rate, maturity, expiry, amount`);
804
- if (!["asc", "desc"].includes(c.dir)) throw new Error(`Invalid direction: ${c.dir}. Must be one of: asc, desc`);
805
- if (!/^0x[a-fA-F0-9]{64}$/.test(c.hash)) throw new Error(`Invalid hash format: ${c.hash}. Must be a 64-character hex string starting with 0x`);
806
- const validation = {
807
- rate: {
808
- field: "rate",
809
- type: "string",
810
- pattern: /^\d+$/,
811
- error: "numeric string"
812
- },
813
- amount: {
814
- field: "assets",
815
- type: "string",
816
- pattern: /^\d+$/,
817
- error: "numeric string"
818
- },
819
- maturity: {
820
- field: "maturity",
821
- type: "number",
822
- validator: (val) => val > 0,
823
- error: "positive number"
824
- },
825
- expiry: {
826
- field: "expiry",
827
- type: "number",
828
- validator: (val) => val > 0,
829
- error: "positive number"
830
- }
831
- }[c.sort];
832
- if (!validation) throw new Error(`Invalid sort field: ${c.sort}`);
833
- const fieldValue = c[validation.field];
834
- if (!fieldValue) throw new Error(`${c.sort} sort requires '${validation.field}' field to be present`);
835
- if (typeof fieldValue !== validation.type) throw new Error(`${c.sort} sort requires '${validation.field}' field of type ${validation.type}`);
836
- if (validation.pattern && !validation.pattern.test(fieldValue)) throw new Error(`Invalid ${validation.field} format: ${fieldValue}. Must be a ${validation.error}`);
837
- if (validation.validator && !validation.validator(fieldValue)) throw new Error(`Invalid ${validation.field} value: ${fieldValue}. Must be a ${validation.error}`);
838
- if (c.page !== void 0) {
839
- if (typeof c.page !== "number" || !Number.isInteger(c.page) || c.page < 1) throw new Error("Invalid page: must be a positive integer");
840
- }
841
- return true;
842
- }
843
- function encode$3(c) {
844
- return Base64.encodeURL(JSON.stringify(c));
845
- }
846
- function decode$3(token$1) {
847
- if (!token$1) return null;
848
- const decoded = JSON.parse(Base64.decode(token$1));
849
- validate(decoded);
850
- return decoded;
851
- }
852
-
853
- //#endregion
854
- //#region src/api/Schema/requests.ts
855
- const MAX_LIMIT = 100;
856
- const DEFAULT_LIMIT = 20;
857
- const PaginationQueryParams = z$1.object({
858
- cursor: z$1.string().optional().refine((val) => {
859
- if (!val) return true;
860
- try {
861
- return decode$3(val) !== null;
862
- } catch (_error) {
863
- return false;
864
- }
865
- }, { message: "Invalid cursor format. Must be a valid base64url-encoded cursor object" }).meta({
866
- description: "Pagination cursor in base64url-encoded format",
867
- example: "eyJzb3J0IjoicHJpY2UiLCJkaXIiOiJkZXNjIiwicHJpY2UiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwiaGFzaCI6IjB4ZGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIifQ"
868
- }),
869
- limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT).meta({
870
- description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
871
- example: 10
872
- })
873
- });
874
- const GetOffersQueryParams = z$1.object({
875
- ...PaginationQueryParams.shape,
876
- side: z$1.enum(["buy", "sell"]).optional().meta({
877
- description: "Side of the offer. Required when using obligation_id.",
878
- example: "buy"
879
- }),
880
- obligation_id: z$1.string().regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).optional().meta({
881
- description: "Offers obligation id. Required when not using offering.",
882
- example: "0x1234567890123456789012345678901234567890123456789012345678901234"
883
- }),
884
- offering: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Offering must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).optional().meta({
885
- description: "Maker address to filter offers by. Alternative to obligation_id + side.",
886
- example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
887
- })
888
- }).superRefine((val, ctx) => {
889
- const hasObligation = val.obligation_id !== void 0;
890
- const hasSide = val.side !== void 0;
891
- const hasOffering = val.offering !== void 0;
892
- if (hasOffering && (hasObligation || hasSide)) {
893
- ctx.addIssue({
894
- code: "custom",
895
- message: "Cannot use both offering and obligation_id/side parameters"
896
- });
897
- return;
898
- }
899
- if (hasOffering) return;
900
- if (!hasObligation || !hasSide) ctx.addIssue({
901
- code: "custom",
902
- message: "Must provide either offering or both obligation_id and side"
903
- });
904
- });
905
- const GetObligationsQueryParams = z$1.object({
906
- ...PaginationQueryParams.shape,
907
- cursor: z$1.string().optional().meta({
908
- description: "Obligation id cursor",
909
- example: "0x1234567890123456789012345678901234567890123456789012345678901234"
910
- })
911
- });
912
- const GetObligationParams = z$1.object({ obligation_id: z$1.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({
913
- description: "Obligation id",
914
- example: "0x1234567890123456789012345678901234567890123456789012345678901234"
915
- }) });
916
- /** Validate a book cursor format: {side, lastRate, offersCursor} */
917
- function isValidBookCursor(cursorString) {
918
- const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
919
- try {
920
- const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
921
- return (v?.side === "buy" || v?.side === "sell") && isNumericString(v?.lastRate) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
922
- } catch {
923
- return false;
924
- }
925
- }
926
- const BookPaginationQueryParams = z$1.object({
927
- cursor: z$1.string().optional().refine((value) => {
928
- if (!value) return true;
929
- return isValidBookCursor(value);
930
- }, { message: "Invalid cursor format. Must be a valid base64url-encoded book cursor object" }).meta({
931
- description: "Pagination cursor in base64url-encoded format for book levels",
932
- example: "eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ"
933
- }),
934
- limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT).meta({
935
- description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
936
- example: 10
937
- })
938
- });
939
- const GetBookParams = z$1.object({
940
- ...BookPaginationQueryParams.shape,
941
- obligation_id: z$1.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({
942
- description: "Obligation id",
943
- example: "0x1234567890123456789012345678901234567890123456789012345678901234"
944
- }),
945
- side: z$1.enum(["buy", "sell"]).meta({
946
- description: "Side of the book (buy or sell).",
947
- example: "buy"
948
- })
949
- });
950
- const schemas = {
951
- get_offers: GetOffersQueryParams,
952
- get_obligations: GetObligationsQueryParams,
953
- get_obligation: GetObligationParams,
954
- get_book: GetBookParams,
955
- validate_offers: z$1.object({
956
- offers: z$1.any().refine((val) => val === void 0 || Array.isArray(val), { message: "'offers' must be an array" }),
957
- calldata: z$1.string().regex(/^0x[a-fA-F0-9]*$/, { message: "'calldata' must be a hex string starting with '0x'" }).optional()
958
- }).superRefine((val, ctx) => {
959
- const hasOffers = val.offers !== void 0;
960
- const hasCalldata = val.calldata !== void 0;
961
- if (hasOffers && hasCalldata) ctx.addIssue({
962
- code: "custom",
963
- message: "Request body must contain either 'offers' or 'calldata', not both"
964
- });
965
- if (!hasOffers && !hasCalldata) ctx.addIssue({
966
- code: "custom",
967
- message: "Request body must contain either 'offers' array or 'calldata' hex string"
968
- });
969
- })
970
- };
971
- function parse(action, query) {
972
- return schemas[action].parse(query);
973
- }
974
- function safeParse(action, query, error) {
975
- return schemas[action].safeParse(query, { error });
976
- }
977
-
978
- //#endregion
979
- //#region src/api/Schema/index.ts
980
- var Schema_exports = /* @__PURE__ */ __export({
981
- BookResponse: () => BookResponse_exports,
982
- BooksController: () => BooksController,
983
- ChainHealth: () => ChainHealth,
984
- ChainsHealthResponse: () => ChainsHealthResponse,
985
- CollectorHealth: () => CollectorHealth,
986
- CollectorsHealthResponse: () => CollectorsHealthResponse,
987
- HealthController: () => HealthController,
988
- ObligationResponse: () => ObligationResponse_exports,
989
- ObligationsController: () => ObligationsController,
990
- OfferResponse: () => OfferResponse_exports,
991
- OffersController: () => OffersController,
992
- OpenApi: () => OpenApi,
993
- RouterStatusResponse: () => RouterStatusResponse,
994
- ValidateController: () => ValidateController,
995
- parse: () => parse,
996
- safeParse: () => safeParse
997
- });
998
-
999
- //#endregion
1000
- //#region src/core/Abi/MetaMorpho.ts
1001
- const MetaMorpho = parseAbi([
1002
- "function balanceOf(address account) view returns (uint256)",
1003
- "function DECIMALS_OFFSET() view returns (uint8)",
1004
- "function totalAssets() view returns (uint256)",
1005
- "function totalSupply() view returns (uint256)",
1006
- "function maxWithdraw(address owner) view returns (uint256 assets)",
1007
- "function asset() view returns (address)",
1008
- "event Transfer(address indexed from, address indexed to, uint256 value)",
1009
- "function withdrawQueue(uint256 index) view returns (bytes32)",
1010
- "function withdrawQueueLength() view returns (uint256)"
1011
- ]);
1012
-
1013
- //#endregion
1014
- //#region src/core/Abi/MetaMorphoFactory.ts
1015
- const MetaMorphoFactory = parseAbi(["event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)", "function isMetaMorpho(address) view returns (bool)"]);
1016
-
1017
- //#endregion
1018
- //#region src/core/Abi/index.ts
1019
- var Abi_exports = /* @__PURE__ */ __export({
1020
- ERC4626: () => ERC4626,
1021
- MetaMorpho: () => MetaMorpho,
1022
- MetaMorphoFactory: () => MetaMorphoFactory,
1023
- Morpho: () => Morpho,
1024
- Oracle: () => Oracle
1025
- });
1026
- const Oracle = [{
1027
- type: "function",
1028
- name: "price",
1029
- inputs: [],
1030
- outputs: [{
1031
- name: "",
1032
- type: "uint256"
1033
- }],
1034
- stateMutability: "view"
1035
- }];
1036
- const ERC4626 = [{
1037
- type: "function",
1038
- name: "asset",
1039
- inputs: [],
1040
- outputs: [{
1041
- name: "",
1042
- type: "address"
1043
- }],
1044
- stateMutability: "view"
1045
- }];
1046
- const Morpho = [
1047
- {
1048
- type: "function",
1049
- name: "collateralOf",
1050
- inputs: [
1051
- {
1052
- name: "",
1053
- type: "address",
1054
- internalType: "address"
1055
- },
1056
- {
1057
- name: "",
1058
- type: "bytes32",
1059
- internalType: "bytes32"
1060
- },
1061
- {
1062
- name: "",
1063
- type: "address",
1064
- internalType: "address"
1065
- }
1066
- ],
1067
- outputs: [{
1068
- name: "",
1069
- type: "uint256",
1070
- internalType: "uint256"
1071
- }],
1072
- stateMutability: "view"
118
+ stateMutability: "view"
119
+ }];
120
+ const ERC4626 = [{
121
+ type: "function",
122
+ name: "asset",
123
+ inputs: [],
124
+ outputs: [{
125
+ name: "",
126
+ type: "address"
127
+ }],
128
+ stateMutability: "view"
129
+ }];
130
+ const Morpho = [
131
+ {
132
+ type: "function",
133
+ name: "collateralOf",
134
+ inputs: [
135
+ {
136
+ name: "",
137
+ type: "address",
138
+ internalType: "address"
139
+ },
140
+ {
141
+ name: "",
142
+ type: "bytes32",
143
+ internalType: "bytes32"
144
+ },
145
+ {
146
+ name: "",
147
+ type: "address",
148
+ internalType: "address"
149
+ }
150
+ ],
151
+ outputs: [{
152
+ name: "",
153
+ type: "uint256",
154
+ internalType: "uint256"
155
+ }],
156
+ stateMutability: "view"
1073
157
  },
1074
158
  {
1075
159
  type: "function",
@@ -1193,8 +277,12 @@ function decode$2(type, data) {
1193
277
  }
1194
278
  function encode$2(type, data) {
1195
279
  switch (type) {
1196
- case CallbackType.BuyVaultV1Callback: return encodeBuyVaultV1Callback(data);
1197
- case CallbackType.SellERC20Callback: return encodeSellERC20Callback(data);
280
+ case CallbackType.BuyVaultV1Callback:
281
+ if (!("vaults" in data)) throw new Error("Invalid callback data");
282
+ return encodeBuyVaultV1Callback(data);
283
+ case CallbackType.SellERC20Callback:
284
+ if (!("collaterals" in data)) throw new Error("Invalid callback data");
285
+ return encodeSellERC20Callback(data);
1198
286
  default: throw new Error("Invalid callback type");
1199
287
  }
1200
288
  }
@@ -1239,6 +327,19 @@ function max$1(a, b) {
1239
327
  function min(a, b) {
1240
328
  return a < b ? a : b;
1241
329
  }
330
+ /**
331
+ * Checks if at most one of the given values is non-zero.
332
+ * @param values - The bigint values to check.
333
+ * @returns True if zero or one value is non-zero, false if two or more are non-zero.
334
+ */
335
+ function atMostOneNonZero(...values) {
336
+ let nonZeroCount = 0;
337
+ for (const value of values) if (value !== 0n) {
338
+ nonZeroCount++;
339
+ if (nonZeroCount > 1) return false;
340
+ }
341
+ return true;
342
+ }
1242
343
 
1243
344
  //#endregion
1244
345
  //#region src/utils/batch.ts
@@ -1522,22 +623,22 @@ const DEFAULT_BATCH_SIZE$1 = 2500;
1522
623
  const MAX_BLOCK_WINDOW = 1e4;
1523
624
  const DEFAULT_BLOCK_WINDOW = 8e3;
1524
625
  async function* streamLogs(parameters) {
1525
- const { client, contractAddress, event, blockNumberGte, blockNumberLte, order: order$1 = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE$1, blockWindow = DEFAULT_BLOCK_WINDOW } = {} } = parameters;
626
+ const { client, contractAddress, event, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE$1, blockWindow = DEFAULT_BLOCK_WINDOW } = {} } = parameters;
1526
627
  if (maxBatchSize > MAX_BATCH_SIZE) throw new InvalidBatchSizeError(maxBatchSize);
1527
628
  if (blockWindow > MAX_BLOCK_WINDOW) throw new InvalidBlockWindowError(blockWindow);
1528
- if (order$1 === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
629
+ if (order === "asc" && blockNumberGte === void 0) throw new MissingBlockNumberError();
1529
630
  const latestBlock = (await getBlock(client, {
1530
631
  blockTag: "latest",
1531
632
  includeTransactions: false
1532
633
  })).number;
1533
634
  let toBlock = 0n;
1534
- if (order$1 === "asc") toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), blockNumberLte ? BigInt(blockNumberLte) : latestBlock);
1535
- if (order$1 === "desc") toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
635
+ if (order === "asc") toBlock = min(BigInt(blockNumberGte) + BigInt(blockWindow), blockNumberLte ? BigInt(blockNumberLte) : latestBlock);
636
+ if (order === "desc") toBlock = blockNumberLte === void 0 ? latestBlock : min(BigInt(blockNumberLte), latestBlock);
1536
637
  let fromBlock = 0n;
1537
- if (order$1 === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
1538
- if (order$1 === "desc") fromBlock = max$1(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
1539
- if (order$1 === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
1540
- if (order$1 === "desc") fromBlock = max$1(fromBlock, toBlock - BigInt(blockWindow));
638
+ if (order === "asc") fromBlock = min(BigInt(blockNumberGte), latestBlock);
639
+ if (order === "desc") fromBlock = max$1(BigInt(blockNumberGte || toBlock - BigInt(blockWindow)), 0n);
640
+ if (order === "asc") toBlock = min(toBlock, fromBlock + BigInt(blockWindow));
641
+ if (order === "desc") fromBlock = max$1(fromBlock, toBlock - BigInt(blockWindow));
1541
642
  if (fromBlock > toBlock) throw new InvalidBlockRangeError(fromBlock, toBlock);
1542
643
  let streaming = true;
1543
644
  while (streaming) {
@@ -1547,29 +648,29 @@ async function* streamLogs(parameters) {
1547
648
  fromBlock,
1548
649
  toBlock
1549
650
  });
1550
- streaming = order$1 === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
651
+ streaming = order === "asc" ? toBlock < (blockNumberLte || latestBlock) : fromBlock > (blockNumberGte || 0n);
1551
652
  if (logs.length === 0 && !streaming) break;
1552
653
  if (logs.length === 0 && streaming) yield {
1553
654
  logs: [],
1554
- blockNumber: order$1 === "asc" ? Number(toBlock) : Number(fromBlock)
655
+ blockNumber: order === "asc" ? Number(toBlock) : Number(fromBlock)
1555
656
  };
1556
657
  logs.sort((a, b) => {
1557
- if (a.blockNumber !== b.blockNumber) return order$1 === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
1558
- if (a.transactionIndex !== b.transactionIndex) return order$1 === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
1559
- return order$1 === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
658
+ if (a.blockNumber !== b.blockNumber) return order === "asc" ? Number(a.blockNumber - b.blockNumber) : Number(b.blockNumber - a.blockNumber);
659
+ if (a.transactionIndex !== b.transactionIndex) return order === "asc" ? a.transactionIndex - b.transactionIndex : b.transactionIndex - a.transactionIndex;
660
+ return order === "asc" ? a.logIndex - b.logIndex : b.logIndex - a.logIndex;
1560
661
  });
1561
662
  for (const logBatch of batch(logs, maxBatchSize)) yield {
1562
663
  logs: logBatch,
1563
- blockNumber: logBatch.length === maxBatchSize ? Number(logBatch[logBatch.length - 1]?.blockNumber) : order$1 === "asc" ? Number(toBlock) : Number(fromBlock)
664
+ blockNumber: logBatch.length === maxBatchSize ? Number(logBatch[logBatch.length - 1]?.blockNumber) : order === "asc" ? Number(toBlock) : Number(fromBlock)
1564
665
  };
1565
- if (order$1 === "asc") {
666
+ if (order === "asc") {
1566
667
  const upperBound = BigInt(blockNumberLte || latestBlock);
1567
668
  const nextFromBlock = min(BigInt(toBlock) + 1n, upperBound);
1568
669
  const nextToBlock = min(toBlock + BigInt(blockWindow) + 1n, upperBound);
1569
670
  fromBlock = nextFromBlock;
1570
671
  toBlock = nextToBlock;
1571
672
  }
1572
- if (order$1 === "desc") {
673
+ if (order === "desc") {
1573
674
  const lowerBound = BigInt(blockNumberGte || 0);
1574
675
  const nextToBlock = max$1(fromBlock - 1n, lowerBound);
1575
676
  const nextFromBlock = max$1(fromBlock - BigInt(blockWindow) - 1n, lowerBound);
@@ -1579,7 +680,7 @@ async function* streamLogs(parameters) {
1579
680
  }
1580
681
  yield {
1581
682
  logs: [],
1582
- blockNumber: order$1 === "asc" ? Number(toBlock) : Number(fromBlock)
683
+ blockNumber: order === "asc" ? Number(toBlock) : Number(fromBlock)
1583
684
  };
1584
685
  }
1585
686
  var InvalidBlockRangeError = class extends BaseError {
@@ -1607,25 +708,185 @@ var MissingBlockNumberError = class extends BaseError {
1607
708
  }
1608
709
  };
1609
710
 
711
+ //#endregion
712
+ //#region src/core/ChainRegistry.ts
713
+ var ChainRegistry_exports = /* @__PURE__ */ __export({ create: () => create$1 });
714
+ function create$1(chains$2) {
715
+ const byId = /* @__PURE__ */ new Map();
716
+ for (const chain of chains$2) byId.set(chain.id, chain);
717
+ return {
718
+ getById: (chainId) => byId.get(chainId),
719
+ list: () => Array.from(byId.values())
720
+ };
721
+ }
722
+
723
+ //#endregion
724
+ //#region src/utils/Random.ts
725
+ var Random_exports = /* @__PURE__ */ __export({
726
+ address: () => address,
727
+ bool: () => bool,
728
+ bytes: () => bytes,
729
+ float: () => float,
730
+ hex: () => hex,
731
+ int: () => int,
732
+ seed: () => seed,
733
+ withSeed: () => withSeed
734
+ });
735
+ let currentRng = Math.random;
736
+ const FNV_OFFSET_BASIS = 2166136261;
737
+ const FNV_PRIME = 16777619;
738
+ const hashSeed = (seed$1) => {
739
+ let hash$1 = FNV_OFFSET_BASIS;
740
+ for (let i = 0; i < seed$1.length; i += 1) {
741
+ hash$1 ^= seed$1.charCodeAt(i);
742
+ hash$1 = Math.imul(hash$1, FNV_PRIME);
743
+ }
744
+ return hash$1 >>> 0;
745
+ };
746
+ const createSeededRng = (seed$1) => {
747
+ let state = hashSeed(seed$1);
748
+ return () => {
749
+ state += 1831565813;
750
+ let t = Math.imul(state ^ state >>> 15, state | 1);
751
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
752
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
753
+ };
754
+ };
755
+ /**
756
+ * Runs a function with a deterministic RNG derived from the given seed.
757
+ */
758
+ function withSeed(seed$1, fn) {
759
+ const previous = currentRng;
760
+ currentRng = createSeededRng(seed$1);
761
+ try {
762
+ return fn();
763
+ } finally {
764
+ currentRng = previous;
765
+ }
766
+ }
767
+ /**
768
+ * Seeds the global RNG for deterministic test runs.
769
+ */
770
+ function seed(seed$1) {
771
+ currentRng = createSeededRng(seed$1);
772
+ }
773
+ /**
774
+ * Returns a deterministic random float in [0, 1).
775
+ */
776
+ function float() {
777
+ return currentRng();
778
+ }
779
+ /**
780
+ * Returns a deterministic random integer in [min, maxExclusive).
781
+ */
782
+ function int(maxExclusive, min$1 = 0) {
783
+ return Math.floor(float() * (maxExclusive - min$1)) + min$1;
784
+ }
785
+ /**
786
+ * Returns a deterministic random boolean.
787
+ */
788
+ function bool(probability = .5) {
789
+ return float() < probability;
790
+ }
791
+ /**
792
+ * Returns deterministic random bytes.
793
+ */
794
+ function bytes(length) {
795
+ const output = new Uint8Array(length);
796
+ for (let i = 0; i < length; i += 1) output[i] = int(256);
797
+ return output;
798
+ }
799
+ /**
800
+ * Returns a deterministic random hex string for the given byte length.
801
+ */
802
+ function hex(byteLength) {
803
+ const output = bytes(byteLength);
804
+ return `0x${Array.from(output, (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
805
+ }
806
+ /**
807
+ * Returns a deterministic random address.
808
+ */
809
+ function address() {
810
+ return hex(20);
811
+ }
812
+
1610
813
  //#endregion
1611
814
  //#region src/utils/zod.ts
815
+ /**
816
+ * Converts a hex string to a padded bytes32.
817
+ * Returns null if the value is not a valid hex string.
818
+ */
819
+ const hexToBytes32 = (val) => {
820
+ if (!isHex(val)) return null;
821
+ return pad(val, { size: 32 });
822
+ };
823
+ /**
824
+ * Converts a numeric string to a padded bytes32.
825
+ * @throws {Error} If parsing fails or value is negative.
826
+ */
827
+ const numericStringToBytes32 = (val) => {
828
+ const num = BigInt(val);
829
+ if (num < 0n) throw new Error("expected bigint to be >=0");
830
+ return pad(numberToHex(num), { size: 32 });
831
+ };
832
+ /**
833
+ * Converts a number or bigint to a padded bytes32.
834
+ * @throws {Error} If value is negative.
835
+ */
836
+ const numericToBytes32 = (val) => {
837
+ const num = BigInt(val);
838
+ if (num < 0n) throw new Error("expected bigint to be >=0");
839
+ return pad(numberToHex(num), { size: 32 });
840
+ };
841
+ /**
842
+ * Transforms a value to a bytes32 hex string.
843
+ * Accepts:
844
+ * - Hex strings (0x...) - pads to 32 bytes if needed
845
+ * - Numeric strings - converts to padded hex
846
+ * - Numbers/bigints - converts to padded hex (must be non-negative)
847
+ */
848
+ const transformBytes32 = (val, ctx) => {
849
+ if (typeof val === "string") {
850
+ const hexResult = hexToBytes32(val);
851
+ if (hexResult !== null) return hexResult;
852
+ try {
853
+ return numericStringToBytes32(val);
854
+ } catch (error) {
855
+ ctx.addIssue({
856
+ code: z$1.ZodIssueCode.custom,
857
+ message: `Not a valid bytes32 value: ${error instanceof Error ? error.message : String(error)}`
858
+ });
859
+ return z$1.NEVER;
860
+ }
861
+ }
862
+ if (typeof val === "number" || typeof val === "bigint") try {
863
+ return numericToBytes32(val);
864
+ } catch (error) {
865
+ ctx.addIssue({
866
+ code: z$1.ZodIssueCode.custom,
867
+ message: `Too small: ${error instanceof Error ? error.message : String(error)}`
868
+ });
869
+ return z$1.NEVER;
870
+ }
871
+ ctx.addIssue({
872
+ code: z$1.ZodIssueCode.custom,
873
+ message: "Not a valid bytes32 value"
874
+ });
875
+ return z$1.NEVER;
876
+ };
1612
877
  const transformHex = (val, ctx) => {
1613
878
  if (isHex(val)) return val;
1614
879
  ctx.addIssue({
1615
- code: "invalid_format",
1616
- input: val,
1617
- format: "hex",
1618
- error: "not a hex"
880
+ code: z$1.ZodIssueCode.custom,
881
+ message: "Invalid hex"
1619
882
  });
1620
883
  return z$1.NEVER;
1621
884
  };
1622
885
  const transformAddress = (val, ctx) => {
1623
886
  if (isAddress(val.toLowerCase())) return val.toLowerCase();
1624
887
  ctx.addIssue({
1625
- code: "invalid_format",
1626
- input: val,
1627
- format: "address",
1628
- error: "not a valid address"
888
+ code: z$1.ZodIssueCode.custom,
889
+ message: "Invalid address"
1629
890
  });
1630
891
  return z$1.NEVER;
1631
892
  };
@@ -1637,7 +898,7 @@ var LLTV_exports = /* @__PURE__ */ __export({
1637
898
  InvalidOptionError: () => InvalidOptionError$1,
1638
899
  LLTVSchema: () => LLTVSchema,
1639
900
  Options: () => Options,
1640
- from: () => from$10
901
+ from: () => from$12
1641
902
  });
1642
903
  const Options = [
1643
904
  .385,
@@ -1656,7 +917,7 @@ const LLTV_SCALED = Options.map((lltv) => BigInt(lltv * 10 ** 18));
1656
917
  * @param lltv - The LLTV option or the scaled LLTV.
1657
918
  * @returns The LLTV.
1658
919
  */
1659
- function from$10(lltv) {
920
+ function from$12(lltv) {
1660
921
  if (typeof lltv === "bigint" && !LLTV_SCALED.includes(lltv)) throw new InvalidLLTVError(lltv);
1661
922
  if (typeof lltv === "bigint") return lltv;
1662
923
  if (typeof lltv === "number" && !Options.includes(lltv)) throw new InvalidOptionError$1(lltv);
@@ -1676,21 +937,21 @@ var InvalidLLTVError = class extends BaseError {
1676
937
  };
1677
938
  const LLTVSchema = z$1.bigint({ coerce: true }).refine((lltv) => {
1678
939
  try {
1679
- from$10(lltv);
940
+ from$12(lltv);
1680
941
  return true;
1681
942
  } catch (_) {
1682
943
  return false;
1683
944
  }
1684
945
  }, { error: () => {
1685
946
  return "Invalid LLTV: must be one of 0.385, 0.625, 0.77, 0.86, 0.915, 0.945, 0.965 or 0.98 (scaled by 1e18)";
1686
- } }).transform((lltv) => from$10(lltv));
947
+ } }).transform((lltv) => from$12(lltv));
1687
948
 
1688
949
  //#endregion
1689
950
  //#region src/core/Collateral.ts
1690
951
  var Collateral_exports = /* @__PURE__ */ __export({
1691
952
  CollateralSchema: () => CollateralSchema,
1692
953
  CollateralsSchema: () => CollateralsSchema,
1693
- from: () => from$9,
954
+ from: () => from$11,
1694
955
  random: () => random$3
1695
956
  });
1696
957
  const CollateralSchema = z$1.object({
@@ -1710,10 +971,10 @@ const CollateralsSchema = z$1.array(CollateralSchema).min(1, { message: "At leas
1710
971
  }
1711
972
  return true;
1712
973
  }, { message: "Collaterals must not contain duplicate assets" });
1713
- const from$9 = (parameters) => {
974
+ const from$11 = (parameters) => {
1714
975
  return {
1715
976
  asset: parameters.asset.toLowerCase(),
1716
- lltv: from$10(parameters.lltv),
977
+ lltv: from$12(parameters.lltv),
1717
978
  oracle: parameters.oracle.toLowerCase()
1718
979
  };
1719
980
  };
@@ -1727,9 +988,9 @@ const from$9 = (parameters) => {
1727
988
  * ```
1728
989
  */
1729
990
  function random$3() {
1730
- return from$9({
1731
- asset: privateKeyToAccount(generatePrivateKey()).address,
1732
- oracle: privateKeyToAccount(generatePrivateKey()).address,
991
+ return from$11({
992
+ asset: address(),
993
+ oracle: address(),
1733
994
  lltv: .965
1734
995
  });
1735
996
  }
@@ -1896,11 +1157,11 @@ var Maturity_exports = /* @__PURE__ */ __export({
1896
1157
  InvalidOptionError: () => InvalidOptionError,
1897
1158
  MaturitySchema: () => MaturitySchema,
1898
1159
  MaturityType: () => MaturityType,
1899
- from: () => from$8
1160
+ from: () => from$10
1900
1161
  });
1901
1162
  const MaturitySchema = z$1.number().int().refine((maturity$1) => {
1902
1163
  try {
1903
- from$8(maturity$1);
1164
+ from$10(maturity$1);
1904
1165
  return true;
1905
1166
  } catch (_e) {
1906
1167
  return false;
@@ -1935,7 +1196,7 @@ const MaturityOptions = {
1935
1196
  * @throws {InvalidDateError} If the maturity is in seconds but not a valid date.
1936
1197
  * @throws {InvalidOptionError} If the maturity is not a valid option.
1937
1198
  */
1938
- function from$8(ts) {
1199
+ function from$10(ts) {
1939
1200
  if (typeof ts === "string") {
1940
1201
  if (ts in MaturityOptions) return MaturityOptions[ts]();
1941
1202
  throw new InvalidOptionError(ts);
@@ -2014,13 +1275,58 @@ var InvalidOptionError = class extends BaseError {
2014
1275
  }
2015
1276
  };
2016
1277
 
1278
+ //#endregion
1279
+ //#region src/utils/Format.ts
1280
+ var Format_exports = /* @__PURE__ */ __export({
1281
+ fromSnakeCase: () => fromSnakeCase$3,
1282
+ stringifyBigint: () => stringifyBigint,
1283
+ toSnakeCase: () => toSnakeCase$1
1284
+ });
1285
+ /**
1286
+ * Formats object keys to snake case.
1287
+ * Preserves ethereum addresses as is.
1288
+ * Converts ethereum addresses to checksummed if used as values.
1289
+ * Stringifies bigint values to strings.
1290
+ */
1291
+ function toSnakeCase$1(obj) {
1292
+ return stringifyBigint(processObject(obj, (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`), (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? getAddress(value.toLowerCase()) : value));
1293
+ }
1294
+ /**
1295
+ * Formats a snake case object to its camel case type.
1296
+ * Preserves ethereum addresses as is.
1297
+ * Converts checksummed ethereum addresses to lowercase if used as values.
1298
+ * @warning Does not unstringify bigint values.
1299
+ */
1300
+ function fromSnakeCase$3(obj) {
1301
+ return processObject(obj, (s) => isAddress(s.toLowerCase()) ? s : s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()), (value) => typeof value === "string" && isAddress(value.toLowerCase()) ? value.toLowerCase() : value);
1302
+ }
1303
+ function processObject(obj, fnKey, fnValue) {
1304
+ if (typeof obj !== "object" || obj === null) return obj;
1305
+ if (Array.isArray(obj)) return obj.map((item) => processObject(item, fnKey, fnValue));
1306
+ return Object.entries(obj).reduce((acc, [key, value]) => {
1307
+ const newKey = fnKey(key);
1308
+ acc[newKey] = typeof value === "object" && value !== null ? processObject(value, fnKey, fnValue) : fnValue(value);
1309
+ return acc;
1310
+ }, {});
1311
+ }
1312
+ function stringifyBigint(value) {
1313
+ if (typeof value === "bigint") return value.toString();
1314
+ if (Array.isArray(value)) return value.map(stringifyBigint);
1315
+ if (value && typeof value === "object") {
1316
+ const out = {};
1317
+ for (const [k, v] of Object.entries(value)) out[k] = stringifyBigint(v);
1318
+ return out;
1319
+ }
1320
+ return value;
1321
+ }
1322
+
2017
1323
  //#endregion
2018
1324
  //#region src/core/Obligation.ts
2019
1325
  var Obligation_exports = /* @__PURE__ */ __export({
2020
1326
  CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
2021
1327
  InvalidObligationError: () => InvalidObligationError,
2022
1328
  ObligationSchema: () => ObligationSchema,
2023
- from: () => from$7,
1329
+ from: () => from$9,
2024
1330
  fromSnakeCase: () => fromSnakeCase$2,
2025
1331
  id: () => id,
2026
1332
  random: () => random$2
@@ -2054,11 +1360,11 @@ const ObligationSchema = z$1.object({
2054
1360
  * });
2055
1361
  * ```
2056
1362
  */
2057
- function from$7(parameters) {
1363
+ function from$9(parameters) {
2058
1364
  try {
2059
1365
  const parsedObligation = ObligationSchema.parse({
2060
1366
  ...parameters,
2061
- maturity: from$8(parameters.maturity)
1367
+ maturity: from$10(parameters.maturity)
2062
1368
  });
2063
1369
  return {
2064
1370
  chainId: parsedObligation.chainId,
@@ -2077,13 +1383,13 @@ function from$7(parameters) {
2077
1383
  * @returns The created obligation. {@link fromSnakeCase.ReturnType}
2078
1384
  */
2079
1385
  function fromSnakeCase$2(input) {
2080
- return from$7(fromSnakeCase$3(input));
1386
+ return from$9(fromSnakeCase$3(input));
2081
1387
  }
2082
1388
  /**
2083
1389
  * Calculates the obligation id based on the smart contract's Obligation struct.
2084
1390
  * The id is computed as keccak256(abi.encode(chainId, loanToken, collaterals, maturity)).
2085
1391
  * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}
2086
- * @param obligation - {@link id.Parameters}
1392
+ * @param parameters - {@link id.Parameters}
2087
1393
  * @returns The obligation id as a 32-byte hex string. {@link id.ReturnType}
2088
1394
  *
2089
1395
  * @example
@@ -2093,9 +1399,9 @@ function fromSnakeCase$2(input) {
2093
1399
  * console.log(id); // 0x1234567890123456789012345678901234567890123456789012345678901234
2094
1400
  * ```
2095
1401
  */
2096
- function id(obligation) {
1402
+ function id(parameters) {
2097
1403
  let lastAsset = "";
2098
- for (const collateral of obligation.collaterals) {
1404
+ for (const collateral of parameters.collaterals) {
2099
1405
  const newAsset = collateral.asset.toLowerCase();
2100
1406
  if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();
2101
1407
  lastAsset = newAsset;
@@ -2122,14 +1428,14 @@ function id(obligation) {
2122
1428
  },
2123
1429
  { type: "uint256" }
2124
1430
  ], [
2125
- BigInt(obligation.chainId),
2126
- obligation.loanToken.toLowerCase(),
2127
- obligation.collaterals.map((c) => ({
1431
+ BigInt(parameters.chainId),
1432
+ parameters.loanToken.toLowerCase(),
1433
+ parameters.collaterals.map((c) => ({
2128
1434
  token: c.asset.toLowerCase(),
2129
1435
  lltv: c.lltv,
2130
1436
  oracle: c.oracle.toLowerCase()
2131
1437
  })),
2132
- BigInt(obligation.maturity)
1438
+ BigInt(parameters.maturity)
2133
1439
  ]));
2134
1440
  }
2135
1441
  /**
@@ -2142,15 +1448,11 @@ function id(obligation) {
2142
1448
  * ```
2143
1449
  */
2144
1450
  function random$2() {
2145
- return from$7({
1451
+ return from$9({
2146
1452
  chainId: 1,
2147
- loanToken: privateKeyToAccount(generatePrivateKey()).address,
2148
- collaterals: [from$9({
2149
- asset: privateKeyToAccount(generatePrivateKey()).address,
2150
- oracle: privateKeyToAccount(generatePrivateKey()).address,
2151
- lltv: .965
2152
- })],
2153
- maturity: from$8("end_of_next_quarter")
1453
+ loanToken: address(),
1454
+ collaterals: [random$3()],
1455
+ maturity: from$10("end_of_next_quarter")
2154
1456
  });
2155
1457
  }
2156
1458
  var InvalidObligationError = class extends BaseError {
@@ -2169,101 +1471,249 @@ var CollateralsAreNotSortedError = class extends BaseError {
2169
1471
  //#endregion
2170
1472
  //#region src/core/Tree.ts
2171
1473
  var Tree_exports = /* @__PURE__ */ __export({
1474
+ DecodeError: () => DecodeError,
1475
+ EncodeError: () => EncodeError,
1476
+ TreeError: () => TreeError,
2172
1477
  VERSION: () => VERSION,
2173
1478
  decode: () => decode$1,
2174
1479
  encode: () => encode$1,
2175
- from: () => from$6
1480
+ encodeUnsigned: () => encodeUnsigned,
1481
+ from: () => from$8,
1482
+ proofs: () => proofs
2176
1483
  });
2177
1484
  const VERSION = 1;
1485
+ const normalizeHash = (hash$1) => hash$1.toLowerCase();
2178
1486
  /**
2179
1487
  * Builds a Merkle tree from a list of offers.
2180
1488
  *
2181
1489
  * Leaves are the offer `hash` values as `bytes32` and are deterministically
2182
- * ordered in ascending lexicographic order so that the resulting root is stable
2183
- * regardless of the input order.
1490
+ * ordered following the StandardMerkleTree leaf ordering so that the resulting
1491
+ * root is stable regardless of the input order.
2184
1492
  *
2185
1493
  * @param offers - Offers to include in the tree.
2186
1494
  * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
1495
+ * @throws {TreeError} If tree building fails due to offer inconsistencies.
2187
1496
  */
2188
- const from$6 = (offers) => {
2189
- const leaves = order(offers).map((offer) => {
2190
- return [offer.hash];
2191
- });
1497
+ const from$8 = (offers) => {
1498
+ const leaves = offers.map((offer) => [hash(offer)]);
2192
1499
  const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
2193
- return Object.assign(tree, { offers });
1500
+ const orderedOffers = orderOffers(tree, offers);
1501
+ return Object.assign(tree, { offers: orderedOffers });
2194
1502
  };
2195
- const byHashAsc = (a, b) => a.localeCompare(b);
2196
- const order = (offers) => {
2197
- return offers.sort((a, b) => byHashAsc(a.hash, b.hash));
1503
+ const orderOffers = (tree, offers) => {
1504
+ const offerByHash = /* @__PURE__ */ new Map();
1505
+ for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
1506
+ const entries = tree.dump().values.map((value) => {
1507
+ const hash$1 = normalizeHash(value.value[0]);
1508
+ const offer = offerByHash.get(hash$1);
1509
+ if (!offer) throw new TreeError(`missing offer for leaf ${hash$1}`);
1510
+ return {
1511
+ offer,
1512
+ treeIndex: value.treeIndex
1513
+ };
1514
+ });
1515
+ entries.sort((a, b) => b.treeIndex - a.treeIndex);
1516
+ return entries.map((item) => item.offer);
2198
1517
  };
2199
1518
  /**
2200
- * Encodes an `Tree` into a Hex string with a version byte prefix and gzipped payload.
1519
+ * Generates merkle proofs for all offers in a tree.
2201
1520
  *
2202
- * - Layout: `0x{vv}{zip...}` where `{vv}` is one-byte version as two hex chars.
2203
- * - Payload is gzip(JSON.stringify([root, ...offers])) with bigint stringified.
1521
+ * Each proof allows independent verification that an offer is included in the tree
1522
+ * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
2204
1523
  *
2205
- * @param tree - The offer Merkle tree to encode.
2206
- * @returns Hex string starting with `0x{vv}` followed by gzipped payload bytes.
2207
- * @throws Error if the given `root` does not match the offers.
2208
- */
2209
- const encode$1 = (tree) => {
2210
- assertRoot(tree.root, tree.offers);
2211
- const offersPayload = tree.offers.map((offer) => ({
2212
- offering: offer.offering,
2213
- assets: offer.assets.toString(),
2214
- rate: offer.rate.toString(),
2215
- maturity: Number(offer.maturity),
2216
- expiry: Number(offer.expiry),
2217
- start: Number(offer.start),
2218
- nonce: offer.nonce.toString(),
2219
- buy: offer.buy,
2220
- chainId: offer.chainId,
2221
- loanToken: offer.loanToken,
2222
- collaterals: offer.collaterals.map((c) => ({
2223
- asset: c.asset,
2224
- oracle: c.oracle,
2225
- lltv: c.lltv.toString()
2226
- })),
2227
- callback: {
2228
- address: offer.callback.address,
2229
- data: offer.callback.data,
2230
- gasLimit: offer.callback.gasLimit.toString()
2231
- },
2232
- signature: offer.signature,
2233
- hash: offer.hash
2234
- }));
2235
- const compressed = gzip(JSON.stringify([tree.root, ...offersPayload]));
2236
- const encoded = new Uint8Array(1 + compressed.length);
2237
- if (VERSION > 255) throw new Error(`Version overflow: ${VERSION}`);
2238
- encoded[0] = VERSION;
2239
- encoded.set(compressed, 1);
1524
+ * @param tree - The {@link Tree} to generate proofs for.
1525
+ * @returns Array of proofs - {@link Proof}
1526
+ */
1527
+ const proofs = (tree) => {
1528
+ return tree.offers.map((offer) => {
1529
+ return {
1530
+ offer,
1531
+ path: tree.getProof([hash(offer)])
1532
+ };
1533
+ });
1534
+ };
1535
+ const assertHex = (value, expectedBytes, name) => {
1536
+ if (typeof value !== "string" || !isHex(value)) throw new DecodeError(`${name} is not a valid hex string`);
1537
+ if (hexToBytes(value).length !== expectedBytes) throw new DecodeError(`${name}: expected ${expectedBytes} bytes`);
1538
+ };
1539
+ const verifySignatureAndRecoverAddress = async (params) => {
1540
+ const { root, signature } = params;
1541
+ assertHex(signature, 65, "signature");
1542
+ const hash$1 = hashMessage({ raw: root });
1543
+ try {
1544
+ return await recoverAddress({
1545
+ hash: hash$1,
1546
+ signature
1547
+ });
1548
+ } catch {
1549
+ throw new DecodeError("signature recovery failed");
1550
+ }
1551
+ };
1552
+ /**
1553
+ * Encodes a merkle tree with signature into hex calldata for onchain broadcast.
1554
+ *
1555
+ * Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
1556
+ * - `{vv}`: 1-byte version (currently 0x01)
1557
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1558
+ * - `{root}`: 32-byte merkle root
1559
+ * - `{signature}`: 65-byte EIP-191 signature over raw root bytes
1560
+ *
1561
+ * Validates signature authenticity and root integrity before encoding.
1562
+ *
1563
+ * @example
1564
+ * ```typescript
1565
+ * const tree = Tree.from(offers);
1566
+ * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1567
+ * const calldata = await Tree.encode(tree, signature);
1568
+ * await broadcast(calldata);
1569
+ * ```
1570
+ *
1571
+ * @example
1572
+ * Manual construction (for advanced users):
1573
+ * ```typescript
1574
+ * const tree = Tree.from(offers);
1575
+ * const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
1576
+ * const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
1577
+ * const signature = await wallet.signMessage({ message: { raw: tree.root } });
1578
+ * const calldata = `${partial}${signature.slice(2)}`;
1579
+ * ```
1580
+ *
1581
+ * @param tree - Merkle tree of offers
1582
+ * @param signature - EIP-191 signature over raw root bytes
1583
+ * @returns Hex-encoded calldata ready for onchain broadcast
1584
+ * @throws {EncodeError} If signature verification fails or root mismatch
1585
+ */
1586
+ const encode$1 = async (tree, signature) => {
1587
+ validateTreeForEncoding(tree);
1588
+ await verifySignatureAndRecoverAddress({
1589
+ root: tree.root,
1590
+ signature
1591
+ });
1592
+ const unsigned = encodeUnsignedBytes(tree);
1593
+ const sigBytes = hexToBytes(signature);
1594
+ const encoded = new Uint8Array(unsigned.length + sigBytes.length);
1595
+ encoded.set(unsigned, 0);
1596
+ encoded.set(sigBytes, unsigned.length);
2240
1597
  return bytesToHex(encoded);
2241
1598
  };
2242
- const assertRoot = (root, offers) => {
2243
- const tree = from$6(offers);
2244
- if (root !== tree.root) throw new Error(`Invalid root: expected ${tree.root}, got ${root}`);
1599
+ /**
1600
+ * Encodes a merkle tree without a signature into hex payload for client-side signing.
1601
+ *
1602
+ * Layout: `0x{vv}{gzip([...offers])}{root}` where:
1603
+ * - `{vv}`: 1-byte version (currently 0x01)
1604
+ * - `{gzip([...offers])}`: gzipped JSON array of serialized offers
1605
+ * - `{root}`: 32-byte merkle root
1606
+ *
1607
+ * Validates root integrity before encoding.
1608
+ *
1609
+ * @param tree - Merkle tree of offers
1610
+ * @returns Hex-encoded unsigned payload
1611
+ * @throws {EncodeError} If root mismatch
1612
+ */
1613
+ const encodeUnsigned = (tree) => {
1614
+ validateTreeForEncoding(tree);
1615
+ return bytesToHex(encodeUnsignedBytes(tree));
1616
+ };
1617
+ const validateTreeForEncoding = (tree) => {
1618
+ if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
1619
+ const computed = from$8(tree.offers);
1620
+ if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
1621
+ };
1622
+ const encodeUnsignedBytes = (tree) => {
1623
+ const offersPayload = tree.offers.map(serialize);
1624
+ const compressed = gzip(JSON.stringify(offersPayload));
1625
+ const rootBytes = hexToBytes(tree.root);
1626
+ const encoded = new Uint8Array(1 + compressed.length + 32);
1627
+ encoded[0] = VERSION;
1628
+ encoded.set(compressed, 1);
1629
+ encoded.set(rootBytes, 1 + compressed.length);
1630
+ return encoded;
2245
1631
  };
2246
1632
  /**
2247
- * Decodes a Hex string produced by {@link encode} back into an `Tree`.
1633
+ * Decodes hex calldata into a validated merkle tree.
1634
+ *
1635
+ * Validates signature before decompression for fail-fast rejection of invalid payloads.
1636
+ * Returns the tree with separately validated signature and recovered signer address.
2248
1637
  *
2249
- * - Ensures the first byte version matches {@link VERSION}.
2250
- * - Decompresses with gunzip, parses JSON, validates offers, and re-checks the root.
1638
+ * Validation order:
1639
+ * 1. Version check
1640
+ * 2. Signature verification (fail-fast, before decompression)
1641
+ * 3. Decompression (only if signature valid)
1642
+ * 4. Root verification (computed from offers vs embedded root)
1643
+ *
1644
+ * @example
1645
+ * ```typescript
1646
+ * const { tree, signature, signer } = await Tree.decode(calldata);
1647
+ * console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
1648
+ * ```
2251
1649
  *
2252
- * @param encoded - Hex string in the form `0x{vv}{zip...}`.
2253
- * @returns A validated `Tree` rebuilt from the offers.
2254
- * @throws Error if the version is invalid or the root does not match the offers.
2255
- */
2256
- const decode$1 = (encoded) => {
2257
- const bytes = hexToBytes(encoded);
2258
- if (bytes.length < 2) throw new Error("Invalid payload: too short");
2259
- const version = bytes[0];
2260
- if (version !== (VERSION & 255)) throw new Error(`Invalid version: expected ${VERSION}, got ${version}`);
2261
- const decoded = ungzip(bytes.slice(1), { to: "string" });
2262
- const data = JSON.parse(decoded);
2263
- const root = data[0];
2264
- const tree = from$6(data.slice(1).map((o) => OfferSchema().parse(o)));
2265
- if (root !== tree.root) throw new Error(`Invalid root: expected ${tree.root}, got ${root}`);
2266
- return tree;
1650
+ * @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
1651
+ * @returns Validated tree, signature, and recovered signer address
1652
+ * @throws {DecodeError} If version invalid, signature invalid, or root mismatch
1653
+ */
1654
+ const decode$1 = async (encoded) => {
1655
+ const bytes$1 = hexToBytes(encoded);
1656
+ if (bytes$1.length < 98) throw new DecodeError("payload too short");
1657
+ const version = bytes$1[0];
1658
+ if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
1659
+ const signature = bytesToHex(bytes$1.slice(-65));
1660
+ const root = bytesToHex(bytes$1.slice(-97, -65));
1661
+ assertHex(root, 32, "root");
1662
+ assertHex(signature, 65, "signature");
1663
+ const signer = await verifySignatureAndRecoverAddress({
1664
+ root,
1665
+ signature
1666
+ });
1667
+ const compressed = bytes$1.slice(1, -97);
1668
+ let decoded;
1669
+ try {
1670
+ decoded = ungzip(compressed, { to: "string" });
1671
+ } catch {
1672
+ throw new DecodeError("decompression failed");
1673
+ }
1674
+ let rawOffers;
1675
+ try {
1676
+ rawOffers = JSON.parse(decoded);
1677
+ } catch {
1678
+ throw new DecodeError("JSON parse failed");
1679
+ }
1680
+ const tree = from$8(rawOffers.map((o) => OfferSchema().parse(o)));
1681
+ if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
1682
+ return {
1683
+ tree,
1684
+ signature,
1685
+ signer
1686
+ };
1687
+ };
1688
+ /**
1689
+ * Error thrown during tree building operations.
1690
+ * Indicates structural issues with the tree (missing offers, inconsistent state).
1691
+ */
1692
+ var TreeError = class extends BaseError {
1693
+ constructor(reason) {
1694
+ super(`Tree error: ${reason}`);
1695
+ _defineProperty(this, "name", "Tree.TreeError");
1696
+ }
1697
+ };
1698
+ /**
1699
+ * Error thrown during tree encoding.
1700
+ * Indicates validation failures (signature, root mismatch, mixed makers).
1701
+ */
1702
+ var EncodeError = class extends BaseError {
1703
+ constructor(reason) {
1704
+ super(`Failed to encode tree: ${reason}`);
1705
+ _defineProperty(this, "name", "Tree.EncodeError");
1706
+ }
1707
+ };
1708
+ /**
1709
+ * Error thrown during tree decoding.
1710
+ * Indicates payload corruption, version mismatch, or validation failures.
1711
+ */
1712
+ var DecodeError = class extends BaseError {
1713
+ constructor(reason) {
1714
+ super(`Failed to decode tree: ${reason}`);
1715
+ _defineProperty(this, "name", "Tree.DecodeError");
1716
+ }
2267
1717
  };
2268
1718
 
2269
1719
  //#endregion
@@ -2271,59 +1721,63 @@ const decode$1 = (encoded) => {
2271
1721
  var Offer_exports = /* @__PURE__ */ __export({
2272
1722
  AccountNotSetError: () => AccountNotSetError,
2273
1723
  InvalidOfferError: () => InvalidOfferError,
2274
- OfferHashSchema: () => OfferHashSchema,
2275
1724
  OfferSchema: () => OfferSchema,
2276
1725
  Status: () => Status,
2277
1726
  consumedEvent: () => consumedEvent,
2278
1727
  decode: () => decode,
2279
1728
  domain: () => domain,
2280
1729
  encode: () => encode,
2281
- from: () => from$5,
1730
+ from: () => from$7,
2282
1731
  fromSnakeCase: () => fromSnakeCase$1,
2283
1732
  hash: () => hash,
2284
1733
  obligationId: () => obligationId,
2285
1734
  random: () => random$1,
1735
+ serialize: () => serialize,
2286
1736
  sign: () => sign,
2287
1737
  signatureMsg: () => signatureMsg,
2288
1738
  toSnakeCase: () => toSnakeCase,
2289
1739
  types: () => types
2290
1740
  });
1741
+ /** Internal symbol for caching the computed hash. */
1742
+ const HASH_CACHE = Symbol("offer.hash");
2291
1743
  let Status = /* @__PURE__ */ function(Status$1) {
2292
1744
  Status$1["VALID"] = "VALID";
2293
1745
  Status$1["SIMULATION_ERROR"] = "SIMULATION_ERROR";
2294
1746
  return Status$1;
2295
1747
  }({});
2296
- const OfferHashSchema = z$1.string().regex(/^0x[0-9a-fA-F]{64}$/, { message: "Hash must be a valid 32-byte hex string" }).transform(transformHex);
2297
- const OfferSchema = (parameters) => {
2298
- const { omitHash = false } = parameters || {};
2299
- let base$1 = z$1.object({
2300
- offering: z$1.string().transform(transformAddress),
1748
+ const OfferSchema = () => {
1749
+ return z$1.object({
1750
+ maker: z$1.string().transform(transformAddress),
2301
1751
  assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
2302
- rate: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
1752
+ obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
1753
+ obligationShares: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
1754
+ price: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
2303
1755
  maturity: MaturitySchema,
2304
1756
  expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
2305
1757
  start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
2306
- nonce: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
1758
+ group: z$1.union([
1759
+ z$1.string(),
1760
+ z$1.number(),
1761
+ z$1.bigint()
1762
+ ]).transform(transformBytes32),
1763
+ session: z$1.union([
1764
+ z$1.string(),
1765
+ z$1.number(),
1766
+ z$1.bigint()
1767
+ ]).optional().default("0x0000000000000000000000000000000000000000000000000000000000000000").transform(transformBytes32),
2307
1768
  buy: z$1.boolean(),
2308
1769
  chainId: z$1.number().min(0).max(Number.MAX_SAFE_INTEGER),
2309
1770
  loanToken: z$1.string().transform(transformAddress),
2310
1771
  collaterals: CollateralsSchema,
2311
1772
  callback: z$1.object({
2312
1773
  address: z$1.string().transform(transformAddress),
2313
- data: z$1.string().transform(transformHex),
2314
- gasLimit: z$1.bigint({ coerce: true }).min(0n).max(maxUint256)
2315
- }),
2316
- signature: z$1.string().regex(/^0x[0-9a-fA-F]{130}$/, { message: "Signature must be a valid 65-byte hex string" }).transform(transformHex).optional(),
2317
- consumed: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional(),
2318
- takeable: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional(),
2319
- blockNumber: z$1.number().int().max(Number.MAX_SAFE_INTEGER).optional()
2320
- });
2321
- if (!omitHash) base$1 = base$1.extend({ hash: OfferHashSchema });
2322
- return base$1.refine((data) => data.start < data.expiry, {
2323
- message: "Start must be before expiry",
1774
+ data: z$1.string().transform(transformHex)
1775
+ })
1776
+ }).refine((data) => data.start < data.expiry, {
1777
+ message: "start must be before expiry",
2324
1778
  path: ["start"]
2325
1779
  }).refine((data) => data.expiry <= data.maturity, {
2326
- message: "Expiry cannot be after maturity",
1780
+ message: "expiry must be before or equal to maturity",
2327
1781
  path: ["expiry"]
2328
1782
  });
2329
1783
  };
@@ -2331,16 +1785,11 @@ const OfferSchema = (parameters) => {
2331
1785
  * Creates an offer from a plain object.
2332
1786
  * @throws {InvalidOfferError} If the offer is invalid.
2333
1787
  * @param input - The offer to create.
2334
- * @returns The created offer with its hash.
1788
+ * @returns The created offer.
2335
1789
  */
2336
- function from$5(input) {
1790
+ function from$7(input) {
2337
1791
  try {
2338
- const parsedOffer = OfferSchema({ omitHash: true }).parse(input);
2339
- const parsedHash = OfferHashSchema.parse(hash(parsedOffer));
2340
- return {
2341
- ...parsedOffer,
2342
- hash: parsedHash
2343
- };
1792
+ return OfferSchema().parse(input);
2344
1793
  } catch (error) {
2345
1794
  throw new InvalidOfferError(error);
2346
1795
  }
@@ -2349,10 +1798,10 @@ function from$5(input) {
2349
1798
  * Creates an offer from a snake case object.
2350
1799
  * @throws {InvalidOfferError} If the offer is invalid.
2351
1800
  * @param input - The offer to create.
2352
- * @returns The created offer with its hash.
1801
+ * @returns The created offer.
2353
1802
  */
2354
1803
  function fromSnakeCase$1(input) {
2355
- return from$5(fromSnakeCase$3(input));
1804
+ return from$7(fromSnakeCase$3(input));
2356
1805
  }
2357
1806
  /**
2358
1807
  * Converts an offer to a snake case object.
@@ -2363,19 +1812,51 @@ function toSnakeCase(offer) {
2363
1812
  return toSnakeCase$1(offer);
2364
1813
  }
2365
1814
  /**
1815
+ * Serializes an offer for merkle tree encoding.
1816
+ * Converts BigInt fields to strings for JSON compatibility.
1817
+ *
1818
+ * @param offer - Offer to serialize
1819
+ * @returns JSON-serializable offer object
1820
+ */
1821
+ const serialize = (offer) => ({
1822
+ maker: offer.maker,
1823
+ assets: offer.assets.toString(),
1824
+ obligationUnits: offer.obligationUnits.toString(),
1825
+ obligationShares: offer.obligationShares.toString(),
1826
+ price: offer.price.toString(),
1827
+ maturity: Number(offer.maturity),
1828
+ expiry: Number(offer.expiry),
1829
+ start: Number(offer.start),
1830
+ group: offer.group,
1831
+ session: offer.session,
1832
+ buy: offer.buy,
1833
+ chainId: offer.chainId,
1834
+ loanToken: offer.loanToken,
1835
+ collaterals: offer.collaterals.map((c) => ({
1836
+ asset: c.asset,
1837
+ oracle: c.oracle,
1838
+ lltv: c.lltv.toString()
1839
+ })),
1840
+ callback: {
1841
+ address: offer.callback.address,
1842
+ data: offer.callback.data
1843
+ },
1844
+ hash: hash(offer)
1845
+ });
1846
+ /**
2366
1847
  * Generates a random Offer.
2367
1848
  * The returned Offer contains randomly generated values.
2368
1849
  * @warning The generated Offer should not be used for production usage.
2369
1850
  * @returns {Offer} A randomly generated Offer object.
2370
1851
  */
2371
1852
  function random$1(config) {
2372
- const chain = config?.chains ? config.chains[Math.floor(Math.random() * config.chains.length)] : chains$1.ethereum;
2373
- const loanToken = config?.loanTokens ? config.loanTokens[Math.floor(Math.random() * config.loanTokens.length)] : privateKeyToAccount(generatePrivateKey()).address;
2374
- const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [privateKeyToAccount(generatePrivateKey()).address];
2375
- const collateralAsset = collateralCandidates[Math.floor(Math.random() * collateralCandidates.length)];
1853
+ const chain = config?.chains ? config.chains[int(config.chains.length)] : chains$1.ethereum;
1854
+ const loanToken = config?.loanTokens ? config.loanTokens[int(config.loanTokens.length)] : address();
1855
+ const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [address()];
1856
+ const collateralAsset = collateralCandidates[int(collateralCandidates.length)];
2376
1857
  const maturityOption = weightedChoice([["end_of_month", 1], ["end_of_next_month", 1]]);
2377
- const maturity$1 = config?.maturity ?? from$8(maturityOption);
2378
- const lltv = from$10(weightedChoice([
1858
+ const maturity$1 = config?.maturity ?? from$10(maturityOption);
1859
+ const lltv = from$12(weightedChoice([
2379
1860
  [.385, 1],
2380
1861
  [.5, 1],
2381
1862
  [.625, 2],
@@ -2386,25 +1867,23 @@ function random$1(config) {
2386
1867
  [.965, 4],
2387
1868
  [.98, 2]
2388
1869
  ]));
2389
- const buy = config?.buy !== void 0 ? config.buy : Math.random() > .5;
1870
+ const buy = config?.buy !== void 0 ? config.buy : bool();
2390
1871
  const ONE = 1000000000000000000n;
2391
1872
  const qMin = buy ? 16 : 4;
2392
1873
  const len = (buy ? 32 : 16) - qMin + 1;
2393
- const ratePairs = Array.from({ length: len }, (_, idx) => {
1874
+ const pricePairs = Array.from({ length: len }, (_, idx) => {
2394
1875
  const q = qMin + idx;
2395
1876
  return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
2396
1877
  });
2397
- const rate = config?.rate ?? weightedChoice(ratePairs);
1878
+ const price = config?.price ?? weightedChoice(pricePairs);
2398
1879
  const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
2399
1880
  const unit = BigInt(10) ** BigInt(loanTokenDecimals);
2400
- const amountBase = BigInt(100 + Math.floor(Math.random() * 999901));
1881
+ const amountBase = BigInt(100 + int(999901));
2401
1882
  const assetsScaled = config?.assets ?? amountBase * unit;
2402
- const consumed = config?.consumed !== void 0 ? config.consumed : Math.random() < .8 ? 0n : assetsScaled * BigInt(1 + Math.floor(Math.random() * 900)) / 1000n;
2403
1883
  const callbackBySide = (() => {
2404
1884
  if (buy) return {
2405
1885
  address: zeroAddress,
2406
- data: "0x",
2407
- gasLimit: 0n
1886
+ data: "0x"
2408
1887
  };
2409
1888
  const sellCallbackAddress = "0x3333333333333333333333333333333333333333";
2410
1889
  const amount = assetsScaled * 1000000000000000000000n;
@@ -2413,34 +1892,33 @@ function random$1(config) {
2413
1892
  data: encodeSellERC20Callback({
2414
1893
  collaterals: [collateralAsset],
2415
1894
  amounts: [amount]
2416
- }),
2417
- gasLimit: 0n
1895
+ })
2418
1896
  };
2419
1897
  })();
2420
- return from$5({
2421
- offering: config?.offering ?? privateKeyToAccount(generatePrivateKey()).address,
1898
+ return from$7({
1899
+ maker: config?.maker ?? address(),
2422
1900
  assets: assetsScaled,
2423
- rate,
1901
+ obligationUnits: config?.obligationUnits ?? 0n,
1902
+ obligationShares: config?.obligationShares ?? 0n,
1903
+ price,
2424
1904
  maturity: maturity$1,
2425
1905
  expiry: config?.expiry ?? maturity$1 - 1,
2426
1906
  start: config?.start ?? maturity$1 - 10,
2427
- nonce: BigInt(Math.floor(Math.random() * 1e6)),
1907
+ group: config?.group ?? hex(32),
1908
+ session: config?.session ?? hex(32),
2428
1909
  buy,
2429
1910
  chainId: chain.id,
2430
1911
  loanToken,
2431
- collaterals: config?.collaterals ?? Array.from({ length: Math.floor(Math.random() * 3) + 1 }, () => ({
1912
+ collaterals: config?.collaterals ?? Array.from({ length: int(3) + 1 }, () => ({
2432
1913
  ...random$3(),
2433
1914
  lltv
2434
1915
  })).sort((a, b) => a.asset.localeCompare(b.asset)),
2435
- callback: config?.callback ?? callbackBySide,
2436
- consumed,
2437
- takeable: config?.takeable ?? assetsScaled - consumed,
2438
- blockNumber: config?.blockNumber ?? Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
1916
+ callback: config?.callback ?? callbackBySide
2439
1917
  });
2440
1918
  }
2441
1919
  const weightedChoice = (pairs) => {
2442
1920
  const total = pairs.reduce((sum, [, weight]) => sum + weight, 0);
2443
- let roll = Math.random() * total;
1921
+ let roll = float() * total;
2444
1922
  for (const [value, weight] of pairs) {
2445
1923
  roll -= weight;
2446
1924
  if (roll < 0) return value;
@@ -2471,7 +1949,7 @@ const types = {
2471
1949
  }],
2472
1950
  Offer: [
2473
1951
  {
2474
- name: "offering",
1952
+ name: "maker",
2475
1953
  type: "address"
2476
1954
  },
2477
1955
  {
@@ -2479,7 +1957,15 @@ const types = {
2479
1957
  type: "uint256"
2480
1958
  },
2481
1959
  {
2482
- name: "rate",
1960
+ name: "obligationUnits",
1961
+ type: "uint256"
1962
+ },
1963
+ {
1964
+ name: "obligationShares",
1965
+ type: "uint256"
1966
+ },
1967
+ {
1968
+ name: "price",
2483
1969
  type: "uint256"
2484
1970
  },
2485
1971
  {
@@ -2491,8 +1977,12 @@ const types = {
2491
1977
  type: "uint256"
2492
1978
  },
2493
1979
  {
2494
- name: "nonce",
2495
- type: "uint256"
1980
+ name: "group",
1981
+ type: "bytes32"
1982
+ },
1983
+ {
1984
+ name: "session",
1985
+ type: "bytes32"
2496
1986
  },
2497
1987
  {
2498
1988
  name: "buy",
@@ -2508,37 +1998,30 @@ const types = {
2508
1998
  },
2509
1999
  {
2510
2000
  name: "callback",
2511
- type: "Callback"
2512
- }
2513
- ],
2514
- Collateral: [
2515
- {
2516
- name: "asset",
2517
- type: "address"
2518
- },
2519
- {
2520
- name: "oracle",
2521
- type: "address"
2522
- },
2523
- {
2524
- name: "lltv",
2525
- type: "uint256"
2001
+ type: "Callback"
2526
2002
  }
2527
2003
  ],
2528
- Callback: [
2004
+ Collateral: [
2529
2005
  {
2530
- name: "address",
2006
+ name: "asset",
2531
2007
  type: "address"
2532
2008
  },
2533
2009
  {
2534
- name: "data",
2535
- type: "bytes"
2010
+ name: "oracle",
2011
+ type: "address"
2536
2012
  },
2537
2013
  {
2538
- name: "gasLimit",
2014
+ name: "lltv",
2539
2015
  type: "uint256"
2540
2016
  }
2541
- ]
2017
+ ],
2018
+ Callback: [{
2019
+ name: "address",
2020
+ type: "address"
2021
+ }, {
2022
+ name: "data",
2023
+ type: "bytes"
2024
+ }]
2542
2025
  };
2543
2026
  /**
2544
2027
  * Signs an array of offers.
@@ -2555,30 +2038,36 @@ async function sign(offers, wallet) {
2555
2038
  });
2556
2039
  }
2557
2040
  function signatureMsg(offers) {
2558
- return from$6(offers).root;
2041
+ return from$8(offers).root;
2559
2042
  }
2560
2043
  function hash(offer) {
2561
- return hashTypedData({
2044
+ const cached = offer[HASH_CACHE];
2045
+ if (cached) return cached;
2046
+ const computed = hashTypedData({
2562
2047
  domain: domain(offer.chainId),
2563
2048
  message: {
2564
- offering: offer.offering.toLowerCase(),
2049
+ maker: offer.maker.toLowerCase(),
2565
2050
  assets: offer.assets,
2566
- rate: offer.rate,
2051
+ obligationUnits: offer.obligationUnits,
2052
+ obligationShares: offer.obligationShares,
2053
+ price: offer.price,
2567
2054
  maturity: BigInt(offer.maturity),
2568
2055
  expiry: BigInt(offer.expiry),
2569
- nonce: offer.nonce,
2056
+ group: offer.group,
2057
+ session: offer.session,
2570
2058
  buy: offer.buy,
2571
2059
  loanToken: offer.loanToken.toLowerCase(),
2572
2060
  collaterals: offer.collaterals,
2573
2061
  callback: {
2574
2062
  address: offer.callback.address.toLowerCase(),
2575
- data: offer.callback.data,
2576
- gasLimit: offer.callback.gasLimit
2063
+ data: offer.callback.data
2577
2064
  }
2578
2065
  },
2579
2066
  primaryType: "Offer",
2580
2067
  types
2581
2068
  });
2069
+ offer[HASH_CACHE] = computed;
2070
+ return computed;
2582
2071
  }
2583
2072
  /**
2584
2073
  * Calculates the obligation id for an offer based on the smart contract's Obligation struct.
@@ -2587,7 +2076,7 @@ function hash(offer) {
2587
2076
  * @returns The obligation id as a 32-byte hex string.
2588
2077
  */
2589
2078
  function obligationId(offer) {
2590
- return id(from$7({
2079
+ return id(from$9({
2591
2080
  chainId: offer.chainId,
2592
2081
  loanToken: offer.loanToken,
2593
2082
  collaterals: offer.collaterals,
@@ -2596,7 +2085,7 @@ function obligationId(offer) {
2596
2085
  }
2597
2086
  const OfferAbi = [
2598
2087
  {
2599
- name: "offering",
2088
+ name: "maker",
2600
2089
  type: "address"
2601
2090
  },
2602
2091
  {
@@ -2604,7 +2093,15 @@ const OfferAbi = [
2604
2093
  type: "uint256"
2605
2094
  },
2606
2095
  {
2607
- name: "rate",
2096
+ name: "obligationUnits",
2097
+ type: "uint256"
2098
+ },
2099
+ {
2100
+ name: "obligationShares",
2101
+ type: "uint256"
2102
+ },
2103
+ {
2104
+ name: "price",
2608
2105
  type: "uint256"
2609
2106
  },
2610
2107
  {
@@ -2616,8 +2113,12 @@ const OfferAbi = [
2616
2113
  type: "uint256"
2617
2114
  },
2618
2115
  {
2619
- name: "nonce",
2620
- type: "uint256"
2116
+ name: "group",
2117
+ type: "bytes32"
2118
+ },
2119
+ {
2120
+ name: "session",
2121
+ type: "bytes32"
2621
2122
  },
2622
2123
  {
2623
2124
  name: "buy",
@@ -2656,85 +2157,74 @@ const OfferAbi = [
2656
2157
  {
2657
2158
  name: "callback",
2658
2159
  type: "tuple",
2659
- components: [
2660
- {
2661
- name: "address",
2662
- type: "address"
2663
- },
2664
- {
2665
- name: "data",
2666
- type: "bytes"
2667
- },
2668
- {
2669
- name: "gasLimit",
2670
- type: "uint256"
2671
- }
2672
- ]
2673
- },
2674
- {
2675
- name: "signature",
2676
- type: "bytes"
2160
+ components: [{
2161
+ name: "address",
2162
+ type: "address"
2163
+ }, {
2164
+ name: "data",
2165
+ type: "bytes"
2166
+ }]
2677
2167
  }
2678
2168
  ];
2679
2169
  function encode(offer) {
2680
2170
  return encodeAbiParameters(OfferAbi, [
2681
- offer.offering,
2171
+ offer.maker,
2682
2172
  offer.assets,
2683
- offer.rate,
2173
+ offer.obligationUnits,
2174
+ offer.obligationShares,
2175
+ offer.price,
2684
2176
  BigInt(offer.maturity),
2685
2177
  BigInt(offer.expiry),
2686
- offer.nonce,
2178
+ offer.group,
2179
+ offer.session,
2687
2180
  offer.buy,
2688
2181
  BigInt(offer.chainId),
2689
2182
  offer.loanToken,
2690
2183
  BigInt(offer.start),
2691
2184
  offer.collaterals,
2692
- offer.callback,
2693
- offer.signature ?? "0x"
2185
+ offer.callback
2694
2186
  ]);
2695
2187
  }
2696
- function decode(data, blockNumber) {
2188
+ function decode(data) {
2697
2189
  let decoded;
2698
2190
  try {
2699
2191
  decoded = decodeAbiParameters(OfferAbi, data);
2700
2192
  } catch (error) {
2701
2193
  throw new InvalidOfferError(error);
2702
2194
  }
2703
- return from$5({
2704
- offering: decoded[0],
2195
+ return from$7({
2196
+ maker: decoded[0],
2705
2197
  assets: decoded[1],
2706
- rate: decoded[2],
2707
- maturity: from$8(Number(decoded[3])),
2708
- expiry: Number(decoded[4]),
2709
- nonce: decoded[5],
2710
- buy: decoded[6],
2711
- chainId: Number(decoded[7]),
2712
- loanToken: decoded[8],
2713
- start: Number(decoded[9]),
2714
- collaterals: decoded[10].map((c) => {
2715
- return from$9({
2198
+ obligationUnits: decoded[2],
2199
+ obligationShares: decoded[3],
2200
+ price: decoded[4],
2201
+ maturity: from$10(Number(decoded[5])),
2202
+ expiry: Number(decoded[6]),
2203
+ group: decoded[7],
2204
+ session: decoded[8],
2205
+ buy: decoded[9],
2206
+ chainId: Number(decoded[10]),
2207
+ loanToken: decoded[11],
2208
+ start: Number(decoded[12]),
2209
+ collaterals: decoded[13].map((c) => {
2210
+ return from$11({
2716
2211
  asset: c.asset,
2717
2212
  oracle: c.oracle,
2718
2213
  lltv: c.lltv
2719
2214
  });
2720
2215
  }),
2721
2216
  callback: {
2722
- address: decoded[11].address,
2723
- data: decoded[11].data,
2724
- gasLimit: decoded[11].gasLimit
2725
- },
2726
- consumed: 0n,
2727
- blockNumber: Number(blockNumber),
2728
- takeable: decoded[1],
2729
- ...decoded[12] === "0x" ? {} : { signature: decoded[12] }
2217
+ address: decoded[14].address,
2218
+ data: decoded[14].data
2219
+ }
2730
2220
  });
2731
2221
  }
2732
2222
  /**
2733
- * ABI for the Consumed event emitted by the Obligation contract.
2223
+ * ABI for the Consume event emitted by the Obligation contract.
2734
2224
  */
2735
2225
  const consumedEvent = {
2736
2226
  type: "event",
2737
- name: "Consumed",
2227
+ name: "Consume",
2738
2228
  inputs: [
2739
2229
  {
2740
2230
  name: "user",
@@ -2743,212 +2233,1524 @@ const consumedEvent = {
2743
2233
  internalType: "address"
2744
2234
  },
2745
2235
  {
2746
- name: "nonce",
2747
- type: "uint256",
2236
+ name: "group",
2237
+ type: "bytes32",
2748
2238
  indexed: true,
2239
+ internalType: "bytes32"
2240
+ },
2241
+ {
2242
+ name: "amount",
2243
+ type: "uint256",
2244
+ indexed: false,
2749
2245
  internalType: "uint256"
2246
+ }
2247
+ ],
2248
+ anonymous: false
2249
+ };
2250
+ var InvalidOfferError = class InvalidOfferError extends BaseError {
2251
+ constructor(error) {
2252
+ super("Invalid offer.", { cause: error });
2253
+ _defineProperty(this, "name", "Offer.InvalidOfferError");
2254
+ }
2255
+ /**
2256
+ * Formats ZodError issues into a human-readable string with line breaks.
2257
+ * @example
2258
+ * "- 'assets': too small, expected >= 0
2259
+ * - 'start': must be before expiry"
2260
+ */
2261
+ static formatDetails(error) {
2262
+ if (!(error instanceof z$1.ZodError)) return error.message;
2263
+ return error.issues.map((issue) => {
2264
+ return `'${issue.path.join(".")}': ${issue.message.trim().toLowerCase()}`;
2265
+ }).join(". ");
2266
+ }
2267
+ /**
2268
+ * Returns the formatted human-readable message.
2269
+ */
2270
+ get formattedMessage() {
2271
+ return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
2272
+ }
2273
+ };
2274
+ var AccountNotSetError = class extends BaseError {
2275
+ constructor() {
2276
+ super("Account not set.");
2277
+ _defineProperty(this, "name", "Offer.AccountNotSetError");
2278
+ }
2279
+ };
2280
+
2281
+ //#endregion
2282
+ //#region src/core/Oracle.ts
2283
+ var Oracle_exports = /* @__PURE__ */ __export({
2284
+ Conversion: () => Conversion,
2285
+ from: () => from$6
2286
+ });
2287
+ /**
2288
+ * Create an Oracle from a plain object.
2289
+ * @param data - The data to create the oracle from.
2290
+ * @returns The created oracle.
2291
+ */
2292
+ function from$6(data) {
2293
+ return {
2294
+ chainId: data.chainId,
2295
+ address: data.address.toLowerCase(),
2296
+ price: data.price ? BigInt(data.price) : null,
2297
+ blockNumber: data.blockNumber
2298
+ };
2299
+ }
2300
+ let Conversion;
2301
+ (function(_Conversion) {
2302
+ function collateralToLoan(amount, params) {
2303
+ return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
2304
+ }
2305
+ _Conversion.collateralToLoan = collateralToLoan;
2306
+ function loanToCollateral(amount, params) {
2307
+ if (params.price === 0n || params.lltv === 0n) return 0n;
2308
+ return amount * 10n ** 36n / params.price * 10n ** 18n / params.lltv;
2309
+ }
2310
+ _Conversion.loanToCollateral = loanToCollateral;
2311
+ })(Conversion || (Conversion = {}));
2312
+
2313
+ //#endregion
2314
+ //#region src/core/Position.ts
2315
+ var Position_exports = /* @__PURE__ */ __export({
2316
+ Type: () => Type,
2317
+ from: () => from$5
2318
+ });
2319
+ let Type = /* @__PURE__ */ function(Type$1) {
2320
+ Type$1["ERC20"] = "erc20";
2321
+ Type$1["VAULT_V1"] = "vault_v1";
2322
+ return Type$1;
2323
+ }({});
2324
+ /**
2325
+ * @constructor
2326
+ * Creates a Position.
2327
+ * @param parameters - {@link from.Parameters}
2328
+ * @returns The created Position. {@link from.ReturnType}
2329
+ */
2330
+ function from$5(parameters) {
2331
+ return {
2332
+ chainId: parameters.chainId,
2333
+ contract: parameters.contract.toLowerCase(),
2334
+ user: parameters.user.toLowerCase(),
2335
+ type: parameters.type,
2336
+ balance: parameters.balance,
2337
+ ...parameters.asset !== void 0 ? { asset: parameters.asset.toLowerCase() } : {},
2338
+ blockNumber: parameters.blockNumber
2339
+ };
2340
+ }
2341
+
2342
+ //#endregion
2343
+ //#region src/core/Quote.ts
2344
+ var Quote_exports = /* @__PURE__ */ __export({
2345
+ InvalidQuoteError: () => InvalidQuoteError,
2346
+ QuoteSchema: () => QuoteSchema,
2347
+ from: () => from$4,
2348
+ fromSnakeCase: () => fromSnakeCase,
2349
+ random: () => random
2350
+ });
2351
+ const QuoteSchema = z$1.object({
2352
+ obligationId: z$1.string().transform(transformHex),
2353
+ ask: z$1.object({ price: z$1.bigint({ coerce: true }).min(0n).max(maxUint256) }),
2354
+ bid: z$1.object({ price: z$1.bigint({ coerce: true }).min(0n).max(maxUint256) })
2355
+ });
2356
+ /**
2357
+ * Creates a quote for a given obligation.
2358
+ * @constructor
2359
+ * @param parameters - {@link from.Parameters}
2360
+ * @returns The created quote. {@link Quote}
2361
+ * @throws If the quote is invalid. {@link InvalidQuoteError}
2362
+ *
2363
+ * @example
2364
+ * ```ts
2365
+ * const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
2366
+ * ```
2367
+ */
2368
+ function from$4(parameters) {
2369
+ try {
2370
+ const parsedQuote = QuoteSchema.parse(parameters);
2371
+ return {
2372
+ obligationId: parsedQuote.obligationId,
2373
+ ask: parsedQuote.ask,
2374
+ bid: parsedQuote.bid
2375
+ };
2376
+ } catch (error) {
2377
+ throw new InvalidQuoteError(error);
2378
+ }
2379
+ }
2380
+ /**
2381
+ * Creates a quote from a snake case object.
2382
+ * @throws If the quote is invalid. {@link InvalidQuoteError}
2383
+ * @param snake - {@link fromSnakeCase.Parameters}
2384
+ * @returns The created quote. {@link fromSnakeCase.ReturnType}
2385
+ */
2386
+ function fromSnakeCase(snake) {
2387
+ return from$4(fromSnakeCase$3(snake));
2388
+ }
2389
+ /**
2390
+ * Generates a random quote.
2391
+ * @returns A randomly generated quote. {@link random.ReturnType}
2392
+ *
2393
+ * @example
2394
+ * ```ts
2395
+ * const quote = Quote.random();
2396
+ * ```
2397
+ */
2398
+ function random() {
2399
+ return from$4({
2400
+ obligationId: id(random$2()),
2401
+ ask: { price: BigInt(int(1e6)) },
2402
+ bid: { price: BigInt(int(1e6)) }
2403
+ });
2404
+ }
2405
+ var InvalidQuoteError = class extends BaseError {
2406
+ constructor(error) {
2407
+ super("Invalid quote.", { cause: error });
2408
+ _defineProperty(this, "name", "Quote.InvalidQuoteError");
2409
+ }
2410
+ };
2411
+
2412
+ //#endregion
2413
+ //#region src/core/Transfer.ts
2414
+ var Transfer_exports = /* @__PURE__ */ __export({ from: () => from$3 });
2415
+ /**
2416
+ * @constructor
2417
+ *
2418
+ * Creates a {@link Transfer}.
2419
+ * @param parameters - {@link from.Parameters}
2420
+ * @returns The created Transfer. {@link from.ReturnType}
2421
+ *
2422
+ * @example
2423
+ * ```ts
2424
+ * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2425
+ * ```
2426
+ */
2427
+ function from$3(parameters) {
2428
+ return {
2429
+ id: parameters.id,
2430
+ chainId: parameters.chainId,
2431
+ contract: parameters.contract.toLowerCase(),
2432
+ from: parameters.from.toLowerCase(),
2433
+ to: parameters.to.toLowerCase(),
2434
+ value: parameters.value,
2435
+ blockNumber: parameters.blockNumber
2436
+ };
2437
+ }
2438
+
2439
+ //#endregion
2440
+ //#region src/core/types.ts
2441
+ const BrandTypeId = Symbol.for("mempool/Brand");
2442
+
2443
+ //#endregion
2444
+ //#region src/api/Schema/OfferResponse.ts
2445
+ var OfferResponse_exports = /* @__PURE__ */ __export({ from: () => from$2 });
2446
+ /**
2447
+ * Creates an `OfferResponse` matching the Solidity Offer struct layout.
2448
+ * @constructor
2449
+ * @param input - {@link Input}
2450
+ * @returns The created `OfferResponse`. {@link OfferResponse}
2451
+ */
2452
+ function from$2(input) {
2453
+ const base$1 = {
2454
+ offer: {
2455
+ obligation: {
2456
+ loan_token: input.loanToken,
2457
+ collaterals: input.collaterals.map((c) => ({
2458
+ token: c.asset,
2459
+ lltv: c.lltv.toString(),
2460
+ oracle: c.oracle
2461
+ })),
2462
+ maturity: input.maturity
2463
+ },
2464
+ buy: input.buy,
2465
+ maker: input.maker,
2466
+ assets: input.assets.toString(),
2467
+ obligation_units: input.obligationUnits.toString(),
2468
+ obligation_shares: input.obligationShares.toString(),
2469
+ start: input.start,
2470
+ expiry: input.expiry,
2471
+ price: input.price.toString(),
2472
+ group: input.group,
2473
+ session: input.session,
2474
+ callback: input.callback.address,
2475
+ callback_data: input.callback.data
2476
+ },
2477
+ offer_hash: input.hash,
2478
+ obligation_id: id({
2479
+ chainId: input.chainId,
2480
+ loanToken: input.loanToken,
2481
+ collaterals: [...input.collaterals],
2482
+ maturity: input.maturity
2483
+ }),
2484
+ chain_id: input.chainId,
2485
+ consumed: input.consumed.toString(),
2486
+ takeable: input.takeable.toString(),
2487
+ block_number: input.blockNumber
2488
+ };
2489
+ if (!input.proof || !input.root || !input.signature) return {
2490
+ ...base$1,
2491
+ root: null,
2492
+ proof: null,
2493
+ signature: null
2494
+ };
2495
+ return {
2496
+ ...base$1,
2497
+ root: input.root.toLowerCase(),
2498
+ proof: input.proof.map((p) => p.toLowerCase()),
2499
+ signature: input.signature.toLowerCase()
2500
+ };
2501
+ }
2502
+
2503
+ //#endregion
2504
+ //#region src/api/Controllers/Payload.ts
2505
+ const API_ERROR_CODES = [
2506
+ "VALIDATION_ERROR",
2507
+ "NOT_FOUND",
2508
+ "INTERNAL_SERVER_ERROR",
2509
+ "BAD_REQUEST"
2510
+ ];
2511
+
2512
+ //#endregion
2513
+ //#region \0@oxc-project+runtime@0.97.0/helpers/decorate.js
2514
+ function __decorate(decorators, target, key, desc) {
2515
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2516
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2517
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2518
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2519
+ }
2520
+
2521
+ //#endregion
2522
+ //#region src/api/Schema/openapi.ts
2523
+ const timestampExample = "2024-01-01T12:00:00.000Z";
2524
+ const offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
2525
+ const obligationCursorExample = "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc";
2526
+ const offerExample = {
2527
+ offer: {
2528
+ obligation: {
2529
+ loan_token: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
2530
+ collaterals: [{
2531
+ token: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
2532
+ lltv: "860000000000000000",
2533
+ oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
2534
+ }],
2535
+ maturity: 1761922799
2750
2536
  },
2751
- {
2752
- name: "amount",
2753
- type: "uint256",
2754
- indexed: false,
2755
- internalType: "uint256"
2756
- }
2537
+ buy: false,
2538
+ maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
2539
+ assets: "369216000000000000000000",
2540
+ obligation_units: "0",
2541
+ obligation_shares: "0",
2542
+ start: 1761922790,
2543
+ expiry: 1761922799,
2544
+ price: "2750000000000000000",
2545
+ group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
2546
+ session: "0x0000000000000000000000000000000000000000000000000000000000000000",
2547
+ callback: "0x1111111111111111111111111111111111111111",
2548
+ callback_data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2549
+ },
2550
+ offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
2551
+ obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc",
2552
+ chain_id: 1,
2553
+ consumed: "0",
2554
+ takeable: "369216000000000000000000",
2555
+ block_number: 0xa7495128adfb1,
2556
+ root: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
2557
+ proof: ["0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba"],
2558
+ signature: "0x1234567890123456789012345678901234567890123456789012345678901234123456789012345678901234567890123456789012345678901234567890123400"
2559
+ };
2560
+ const collectorsHealthExample = {
2561
+ name: "offers",
2562
+ chain_id: 1,
2563
+ block_number: 21345678,
2564
+ updated_at: timestampExample,
2565
+ lag: 0,
2566
+ status: "live",
2567
+ initialized: true
2568
+ };
2569
+ const chainsHealthExample = {
2570
+ chain_id: 1,
2571
+ local_block_number: 21345678,
2572
+ remote_block_number: 21345690,
2573
+ updated_at: timestampExample,
2574
+ initialized: true
2575
+ };
2576
+ const missingCollectorExample = {
2577
+ chain_id: 1,
2578
+ name: "offers"
2579
+ };
2580
+ const validateOfferExample = {
2581
+ maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
2582
+ assets: "369216000000000000000000",
2583
+ obligation_units: "0",
2584
+ obligation_shares: "0",
2585
+ price: "2750000000000000000",
2586
+ maturity: 1761922799,
2587
+ expiry: 1761922799,
2588
+ start: 1761922790,
2589
+ group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
2590
+ session: "0x0000000000000000000000000000000000000000000000000000000000000000",
2591
+ buy: false,
2592
+ chain_id: 1,
2593
+ loan_token: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
2594
+ collaterals: [{
2595
+ asset: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
2596
+ oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401",
2597
+ lltv: "860000000000000000"
2598
+ }],
2599
+ callback: {
2600
+ address: "0x1111111111111111111111111111111111111111",
2601
+ data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
2602
+ }
2603
+ };
2604
+ const routerStatusExample = {
2605
+ status: "live",
2606
+ initialized: true,
2607
+ missing_chains: [],
2608
+ missing_collectors: []
2609
+ };
2610
+ var Meta = class {};
2611
+ __decorate([ApiProperty({
2612
+ type: "string",
2613
+ example: timestampExample
2614
+ })], Meta.prototype, "timestamp", void 0);
2615
+ var SuccessResponse = class {};
2616
+ __decorate([ApiProperty({ type: () => Meta })], SuccessResponse.prototype, "meta", void 0);
2617
+ var ErrorResponse = class {};
2618
+ __decorate([ApiProperty({
2619
+ type: "string",
2620
+ enum: API_ERROR_CODES,
2621
+ example: "VALIDATION_ERROR"
2622
+ })], ErrorResponse.prototype, "code", void 0);
2623
+ __decorate([ApiProperty({
2624
+ type: "string",
2625
+ example: "Limit must be greater than 0."
2626
+ })], ErrorResponse.prototype, "message", void 0);
2627
+ __decorate([ApiProperty({
2628
+ type: "object",
2629
+ example: [{
2630
+ field: "limit",
2631
+ issue: "Limit must be greater than 0."
2632
+ }]
2633
+ })], ErrorResponse.prototype, "details", void 0);
2634
+ var BadRequestResponse = class {};
2635
+ __decorate([ApiProperty({ type: () => ErrorResponse })], BadRequestResponse.prototype, "error", void 0);
2636
+ __decorate([ApiProperty({ type: () => Meta })], BadRequestResponse.prototype, "meta", void 0);
2637
+ var CollateralResponse = class {};
2638
+ __decorate([ApiProperty({
2639
+ type: "string",
2640
+ example: "0x34Cf890dB685FC536E05652FB41f02090c3fb751"
2641
+ })], CollateralResponse.prototype, "token", void 0);
2642
+ __decorate([ApiProperty({
2643
+ type: "string",
2644
+ example: "860000000000000000"
2645
+ })], CollateralResponse.prototype, "lltv", void 0);
2646
+ __decorate([ApiProperty({
2647
+ type: "string",
2648
+ example: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
2649
+ })], CollateralResponse.prototype, "oracle", void 0);
2650
+ var ValidateCollateralRequest = class {};
2651
+ __decorate([ApiProperty({
2652
+ type: "string",
2653
+ example: validateOfferExample.collaterals[0].asset
2654
+ })], ValidateCollateralRequest.prototype, "asset", void 0);
2655
+ __decorate([ApiProperty({
2656
+ type: "string",
2657
+ example: validateOfferExample.collaterals[0].oracle
2658
+ })], ValidateCollateralRequest.prototype, "oracle", void 0);
2659
+ __decorate([ApiProperty({
2660
+ type: "string",
2661
+ example: validateOfferExample.collaterals[0].lltv
2662
+ })], ValidateCollateralRequest.prototype, "lltv", void 0);
2663
+ var ValidateCallbackRequest = class {};
2664
+ __decorate([ApiProperty({
2665
+ type: "string",
2666
+ example: validateOfferExample.callback.address
2667
+ })], ValidateCallbackRequest.prototype, "address", void 0);
2668
+ __decorate([ApiProperty({
2669
+ type: "string",
2670
+ example: validateOfferExample.callback.data
2671
+ })], ValidateCallbackRequest.prototype, "data", void 0);
2672
+ var AskResponse = class {};
2673
+ __decorate([ApiProperty({
2674
+ type: "string",
2675
+ example: "1000000000000000000"
2676
+ })], AskResponse.prototype, "price", void 0);
2677
+ var BidResponse = class {};
2678
+ __decorate([ApiProperty({
2679
+ type: "string",
2680
+ example: "1000000000000000000"
2681
+ })], BidResponse.prototype, "price", void 0);
2682
+ var ObligationOfferResponse = class {};
2683
+ __decorate([ApiProperty({
2684
+ type: "string",
2685
+ example: offerExample.offer.obligation.loan_token
2686
+ })], ObligationOfferResponse.prototype, "loan_token", void 0);
2687
+ __decorate([ApiProperty({
2688
+ type: () => [CollateralResponse],
2689
+ example: offerExample.offer.obligation.collaterals
2690
+ })], ObligationOfferResponse.prototype, "collaterals", void 0);
2691
+ __decorate([ApiProperty({
2692
+ type: "number",
2693
+ example: offerExample.offer.obligation.maturity
2694
+ })], ObligationOfferResponse.prototype, "maturity", void 0);
2695
+ var OfferDataResponse = class {};
2696
+ __decorate([ApiProperty({
2697
+ type: () => ObligationOfferResponse,
2698
+ example: offerExample.offer.obligation
2699
+ })], OfferDataResponse.prototype, "obligation", void 0);
2700
+ __decorate([ApiProperty({
2701
+ type: "boolean",
2702
+ example: offerExample.offer.buy
2703
+ })], OfferDataResponse.prototype, "buy", void 0);
2704
+ __decorate([ApiProperty({
2705
+ type: "string",
2706
+ example: offerExample.offer.maker
2707
+ })], OfferDataResponse.prototype, "maker", void 0);
2708
+ __decorate([ApiProperty({
2709
+ type: "string",
2710
+ example: offerExample.offer.assets
2711
+ })], OfferDataResponse.prototype, "assets", void 0);
2712
+ __decorate([ApiProperty({
2713
+ type: "string",
2714
+ example: offerExample.offer.obligation_units
2715
+ })], OfferDataResponse.prototype, "obligation_units", void 0);
2716
+ __decorate([ApiProperty({
2717
+ type: "string",
2718
+ example: offerExample.offer.obligation_shares
2719
+ })], OfferDataResponse.prototype, "obligation_shares", void 0);
2720
+ __decorate([ApiProperty({
2721
+ type: "number",
2722
+ example: offerExample.offer.start
2723
+ })], OfferDataResponse.prototype, "start", void 0);
2724
+ __decorate([ApiProperty({
2725
+ type: "number",
2726
+ example: offerExample.offer.expiry
2727
+ })], OfferDataResponse.prototype, "expiry", void 0);
2728
+ __decorate([ApiProperty({
2729
+ type: "string",
2730
+ example: offerExample.offer.price
2731
+ })], OfferDataResponse.prototype, "price", void 0);
2732
+ __decorate([ApiProperty({
2733
+ type: "string",
2734
+ example: offerExample.offer.group
2735
+ })], OfferDataResponse.prototype, "group", void 0);
2736
+ __decorate([ApiProperty({
2737
+ type: "string",
2738
+ example: offerExample.offer.session
2739
+ })], OfferDataResponse.prototype, "session", void 0);
2740
+ __decorate([ApiProperty({
2741
+ type: "string",
2742
+ example: offerExample.offer.callback
2743
+ })], OfferDataResponse.prototype, "callback", void 0);
2744
+ __decorate([ApiProperty({
2745
+ type: "string",
2746
+ example: offerExample.offer.callback_data
2747
+ })], OfferDataResponse.prototype, "callback_data", void 0);
2748
+ var OfferListItemResponse = class {};
2749
+ __decorate([ApiProperty({
2750
+ type: () => OfferDataResponse,
2751
+ example: offerExample.offer
2752
+ })], OfferListItemResponse.prototype, "offer", void 0);
2753
+ __decorate([ApiProperty({
2754
+ type: "string",
2755
+ example: offerExample.offer_hash
2756
+ })], OfferListItemResponse.prototype, "offer_hash", void 0);
2757
+ __decorate([ApiProperty({
2758
+ type: "string",
2759
+ example: offerExample.obligation_id
2760
+ })], OfferListItemResponse.prototype, "obligation_id", void 0);
2761
+ __decorate([ApiProperty({
2762
+ type: "number",
2763
+ example: offerExample.chain_id
2764
+ })], OfferListItemResponse.prototype, "chain_id", void 0);
2765
+ __decorate([ApiProperty({
2766
+ type: "string",
2767
+ example: offerExample.consumed
2768
+ })], OfferListItemResponse.prototype, "consumed", void 0);
2769
+ __decorate([ApiProperty({
2770
+ type: "string",
2771
+ example: offerExample.takeable
2772
+ })], OfferListItemResponse.prototype, "takeable", void 0);
2773
+ __decorate([ApiProperty({
2774
+ type: "number",
2775
+ example: offerExample.block_number
2776
+ })], OfferListItemResponse.prototype, "block_number", void 0);
2777
+ __decorate([ApiProperty({
2778
+ type: "string",
2779
+ nullable: true,
2780
+ example: offerExample.root
2781
+ })], OfferListItemResponse.prototype, "root", void 0);
2782
+ __decorate([ApiProperty({
2783
+ type: [String],
2784
+ nullable: true,
2785
+ example: offerExample.proof
2786
+ })], OfferListItemResponse.prototype, "proof", void 0);
2787
+ __decorate([ApiProperty({
2788
+ type: "string",
2789
+ nullable: true,
2790
+ example: offerExample.signature
2791
+ })], OfferListItemResponse.prototype, "signature", void 0);
2792
+ var ObligationResponse = class {};
2793
+ __decorate([ApiProperty({
2794
+ type: "string",
2795
+ example: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67"
2796
+ })], ObligationResponse.prototype, "id", void 0);
2797
+ __decorate([ApiProperty({
2798
+ type: "number",
2799
+ example: 1
2800
+ })], ObligationResponse.prototype, "chain_id", void 0);
2801
+ __decorate([ApiProperty({
2802
+ type: "string",
2803
+ example: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078"
2804
+ })], ObligationResponse.prototype, "loan_token", void 0);
2805
+ __decorate([ApiProperty({ type: () => [CollateralResponse] })], ObligationResponse.prototype, "collaterals", void 0);
2806
+ __decorate([ApiProperty({
2807
+ type: "number",
2808
+ example: 1761922800
2809
+ })], ObligationResponse.prototype, "maturity", void 0);
2810
+ __decorate([ApiProperty({ type: () => AskResponse })], ObligationResponse.prototype, "ask", void 0);
2811
+ __decorate([ApiProperty({ type: () => BidResponse })], ObligationResponse.prototype, "bid", void 0);
2812
+ var ObligationListResponse = class extends SuccessResponse {};
2813
+ __decorate([ApiProperty({
2814
+ type: "string",
2815
+ nullable: true,
2816
+ example: obligationCursorExample
2817
+ })], ObligationListResponse.prototype, "cursor", void 0);
2818
+ __decorate([ApiProperty({
2819
+ type: () => [ObligationResponse],
2820
+ description: "List of obligations with takable offers."
2821
+ })], ObligationListResponse.prototype, "data", void 0);
2822
+ var ObligationSingleSuccessResponse = class extends SuccessResponse {};
2823
+ __decorate([ApiProperty({
2824
+ type: "string",
2825
+ nullable: true,
2826
+ example: null
2827
+ })], ObligationSingleSuccessResponse.prototype, "cursor", void 0);
2828
+ __decorate([ApiProperty({
2829
+ type: () => ObligationResponse,
2830
+ description: "Obligation details."
2831
+ })], ObligationSingleSuccessResponse.prototype, "data", void 0);
2832
+ var OfferListResponse = class extends SuccessResponse {};
2833
+ __decorate([ApiProperty({
2834
+ type: "string",
2835
+ nullable: true,
2836
+ example: offerCursorExample
2837
+ })], OfferListResponse.prototype, "cursor", void 0);
2838
+ __decorate([ApiProperty({
2839
+ type: () => [OfferListItemResponse],
2840
+ description: "Offers matching the provided filters.",
2841
+ example: [offerExample]
2842
+ })], OfferListResponse.prototype, "data", void 0);
2843
+ var MissingCollectorResponse = class {};
2844
+ __decorate([ApiProperty({
2845
+ type: "number",
2846
+ example: missingCollectorExample.chain_id
2847
+ })], MissingCollectorResponse.prototype, "chain_id", void 0);
2848
+ __decorate([ApiProperty({
2849
+ type: "string",
2850
+ example: missingCollectorExample.name
2851
+ })], MissingCollectorResponse.prototype, "name", void 0);
2852
+ var RouterStatusDataResponse = class {};
2853
+ __decorate([ApiProperty({
2854
+ type: "string",
2855
+ enum: ["live", "syncing"],
2856
+ example: routerStatusExample.status
2857
+ })], RouterStatusDataResponse.prototype, "status", void 0);
2858
+ __decorate([ApiProperty({
2859
+ type: "boolean",
2860
+ example: routerStatusExample.initialized
2861
+ })], RouterStatusDataResponse.prototype, "initialized", void 0);
2862
+ __decorate([ApiProperty({
2863
+ type: () => [Number],
2864
+ example: routerStatusExample.missing_chains,
2865
+ description: "Configured chain ids missing initialization rows."
2866
+ })], RouterStatusDataResponse.prototype, "missing_chains", void 0);
2867
+ __decorate([ApiProperty({
2868
+ type: () => [MissingCollectorResponse],
2869
+ example: routerStatusExample.missing_collectors,
2870
+ description: "Collectors missing initialization rows."
2871
+ })], RouterStatusDataResponse.prototype, "missing_collectors", void 0);
2872
+ var RouterStatusSuccessResponse = class extends SuccessResponse {};
2873
+ __decorate([ApiProperty({
2874
+ type: () => RouterStatusDataResponse,
2875
+ description: "Aggregated router status.",
2876
+ example: routerStatusExample
2877
+ })], RouterStatusSuccessResponse.prototype, "data", void 0);
2878
+ var CollectorHealthResponse = class {};
2879
+ __decorate([ApiProperty({
2880
+ type: "string",
2881
+ example: collectorsHealthExample.name
2882
+ })], CollectorHealthResponse.prototype, "name", void 0);
2883
+ __decorate([ApiProperty({
2884
+ type: "number",
2885
+ example: collectorsHealthExample.chain_id
2886
+ })], CollectorHealthResponse.prototype, "chain_id", void 0);
2887
+ __decorate([ApiProperty({
2888
+ type: "number",
2889
+ nullable: true,
2890
+ example: collectorsHealthExample.block_number
2891
+ })], CollectorHealthResponse.prototype, "block_number", void 0);
2892
+ __decorate([ApiProperty({
2893
+ type: "string",
2894
+ nullable: true,
2895
+ example: collectorsHealthExample.updated_at
2896
+ })], CollectorHealthResponse.prototype, "updated_at", void 0);
2897
+ __decorate([ApiProperty({
2898
+ type: "number",
2899
+ nullable: true,
2900
+ example: collectorsHealthExample.lag
2901
+ })], CollectorHealthResponse.prototype, "lag", void 0);
2902
+ __decorate([ApiProperty({
2903
+ type: "string",
2904
+ enum: [
2905
+ "live",
2906
+ "lagging",
2907
+ "unknown"
2757
2908
  ],
2758
- anonymous: false
2909
+ example: collectorsHealthExample.status
2910
+ })], CollectorHealthResponse.prototype, "status", void 0);
2911
+ __decorate([ApiProperty({
2912
+ type: "boolean",
2913
+ example: collectorsHealthExample.initialized
2914
+ })], CollectorHealthResponse.prototype, "initialized", void 0);
2915
+ var CollectorsHealthSuccessResponse = class extends SuccessResponse {};
2916
+ __decorate([ApiProperty({
2917
+ type: () => [CollectorHealthResponse],
2918
+ description: "Collectors health details and sync status.",
2919
+ example: [collectorsHealthExample]
2920
+ })], CollectorsHealthSuccessResponse.prototype, "data", void 0);
2921
+ var ChainHealthResponse = class {};
2922
+ __decorate([ApiProperty({
2923
+ type: "number",
2924
+ example: chainsHealthExample.chain_id
2925
+ })], ChainHealthResponse.prototype, "chain_id", void 0);
2926
+ __decorate([ApiProperty({
2927
+ type: "number",
2928
+ nullable: true,
2929
+ example: chainsHealthExample.local_block_number
2930
+ })], ChainHealthResponse.prototype, "local_block_number", void 0);
2931
+ __decorate([ApiProperty({
2932
+ type: "number",
2933
+ nullable: true,
2934
+ example: chainsHealthExample.remote_block_number
2935
+ })], ChainHealthResponse.prototype, "remote_block_number", void 0);
2936
+ __decorate([ApiProperty({
2937
+ type: "string",
2938
+ nullable: true,
2939
+ example: chainsHealthExample.updated_at
2940
+ })], ChainHealthResponse.prototype, "updated_at", void 0);
2941
+ __decorate([ApiProperty({
2942
+ type: "boolean",
2943
+ example: chainsHealthExample.initialized
2944
+ })], ChainHealthResponse.prototype, "initialized", void 0);
2945
+ var ChainsHealthSuccessResponse = class extends SuccessResponse {};
2946
+ __decorate([ApiProperty({
2947
+ type: () => [ChainHealthResponse],
2948
+ description: "Latest processed block per chain.",
2949
+ example: [chainsHealthExample]
2950
+ })], ChainsHealthSuccessResponse.prototype, "data", void 0);
2951
+ var ValidateOfferRequest = class {};
2952
+ __decorate([ApiProperty({
2953
+ type: "string",
2954
+ example: validateOfferExample.maker
2955
+ })], ValidateOfferRequest.prototype, "maker", void 0);
2956
+ __decorate([ApiProperty({
2957
+ type: "string",
2958
+ example: validateOfferExample.assets
2959
+ })], ValidateOfferRequest.prototype, "assets", void 0);
2960
+ __decorate([ApiProperty({
2961
+ type: "string",
2962
+ example: validateOfferExample.obligation_units,
2963
+ required: false
2964
+ })], ValidateOfferRequest.prototype, "obligation_units", void 0);
2965
+ __decorate([ApiProperty({
2966
+ type: "string",
2967
+ example: validateOfferExample.obligation_shares,
2968
+ required: false
2969
+ })], ValidateOfferRequest.prototype, "obligation_shares", void 0);
2970
+ __decorate([ApiProperty({
2971
+ type: "string",
2972
+ example: validateOfferExample.price
2973
+ })], ValidateOfferRequest.prototype, "price", void 0);
2974
+ __decorate([ApiProperty({
2975
+ type: "number",
2976
+ example: validateOfferExample.maturity
2977
+ })], ValidateOfferRequest.prototype, "maturity", void 0);
2978
+ __decorate([ApiProperty({
2979
+ type: "number",
2980
+ example: validateOfferExample.expiry
2981
+ })], ValidateOfferRequest.prototype, "expiry", void 0);
2982
+ __decorate([ApiProperty({
2983
+ type: "number",
2984
+ example: validateOfferExample.start
2985
+ })], ValidateOfferRequest.prototype, "start", void 0);
2986
+ __decorate([ApiProperty({
2987
+ type: "string",
2988
+ example: validateOfferExample.group
2989
+ })], ValidateOfferRequest.prototype, "group", void 0);
2990
+ __decorate([ApiProperty({
2991
+ type: "string",
2992
+ example: validateOfferExample.session
2993
+ })], ValidateOfferRequest.prototype, "session", void 0);
2994
+ __decorate([ApiProperty({
2995
+ type: "boolean",
2996
+ example: validateOfferExample.buy
2997
+ })], ValidateOfferRequest.prototype, "buy", void 0);
2998
+ __decorate([ApiProperty({
2999
+ type: "number",
3000
+ example: validateOfferExample.chain_id
3001
+ })], ValidateOfferRequest.prototype, "chain_id", void 0);
3002
+ __decorate([ApiProperty({
3003
+ type: "string",
3004
+ example: validateOfferExample.loan_token
3005
+ })], ValidateOfferRequest.prototype, "loan_token", void 0);
3006
+ __decorate([ApiProperty({
3007
+ type: () => [ValidateCollateralRequest],
3008
+ example: validateOfferExample.collaterals
3009
+ })], ValidateOfferRequest.prototype, "collaterals", void 0);
3010
+ __decorate([ApiProperty({
3011
+ type: () => ValidateCallbackRequest,
3012
+ example: validateOfferExample.callback
3013
+ })], ValidateOfferRequest.prototype, "callback", void 0);
3014
+ var ValidateOffersRequest = class {};
3015
+ __decorate([ApiProperty({
3016
+ type: () => [ValidateOfferRequest],
3017
+ description: "Array of offers in snake_case format. Required, non-empty.",
3018
+ required: true
3019
+ })], ValidateOffersRequest.prototype, "offers", void 0);
3020
+ var ValidationSuccessDataResponse = class {};
3021
+ __decorate([ApiProperty({
3022
+ type: "string",
3023
+ description: "Unsigned payload: version (1B) + gzip(offers) + root (32B).",
3024
+ example: "0x01789c..."
3025
+ })], ValidationSuccessDataResponse.prototype, "payload", void 0);
3026
+ __decorate([ApiProperty({
3027
+ type: "string",
3028
+ description: "Merkle tree root to sign with EIP-191.",
3029
+ example: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427"
3030
+ })], ValidationSuccessDataResponse.prototype, "root", void 0);
3031
+ var ValidationSuccessResponse = class extends SuccessResponse {};
3032
+ __decorate([ApiProperty({
3033
+ type: "string",
3034
+ nullable: true,
3035
+ example: null
3036
+ })], ValidationSuccessResponse.prototype, "cursor", void 0);
3037
+ __decorate([ApiProperty({
3038
+ type: () => ValidationSuccessDataResponse,
3039
+ description: "Payload and root for client-side signing."
3040
+ })], ValidationSuccessResponse.prototype, "data", void 0);
3041
+ var ValidationIssueResponse = class {};
3042
+ __decorate([ApiProperty({
3043
+ type: "number",
3044
+ description: "0-indexed position of the failed offer in the request array.",
3045
+ example: 0
3046
+ })], ValidationIssueResponse.prototype, "index", void 0);
3047
+ __decorate([ApiProperty({
3048
+ type: "string",
3049
+ description: "Gatekeeper rule name that rejected the offer.",
3050
+ example: "no_buy"
3051
+ })], ValidationIssueResponse.prototype, "rule", void 0);
3052
+ __decorate([ApiProperty({
3053
+ type: "string",
3054
+ description: "Human-readable rejection reason.",
3055
+ example: "Buy offers are not supported"
3056
+ })], ValidationIssueResponse.prototype, "message", void 0);
3057
+ var ValidationFailureDataResponse = class {};
3058
+ __decorate([ApiProperty({
3059
+ type: () => [ValidationIssueResponse],
3060
+ description: "List of validation issues. Returned when any offer fails validation."
3061
+ })], ValidationFailureDataResponse.prototype, "issues", void 0);
3062
+ var ValidationFailureResponse = class extends SuccessResponse {};
3063
+ __decorate([ApiProperty({
3064
+ type: "string",
3065
+ nullable: true,
3066
+ example: null
3067
+ })], ValidationFailureResponse.prototype, "cursor", void 0);
3068
+ __decorate([ApiProperty({
3069
+ type: () => ValidationFailureDataResponse,
3070
+ description: "List of validation issues. Returned when any offer fails validation."
3071
+ })], ValidationFailureResponse.prototype, "data", void 0);
3072
+ var BookLevelResponse = class {};
3073
+ __decorate([ApiProperty({
3074
+ type: "string",
3075
+ example: "2750000000000000000"
3076
+ })], BookLevelResponse.prototype, "price", void 0);
3077
+ __decorate([ApiProperty({
3078
+ type: "string",
3079
+ example: "369216000000000000000000"
3080
+ })], BookLevelResponse.prototype, "assets", void 0);
3081
+ __decorate([ApiProperty({
3082
+ type: "number",
3083
+ example: 5
3084
+ })], BookLevelResponse.prototype, "count", void 0);
3085
+ const positionExample = {
3086
+ chain_id: 1,
3087
+ contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
3088
+ user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
3089
+ reserved: "200000000000000000000",
3090
+ block_number: 21345678
3091
+ };
3092
+ var PositionListItemResponse = class {};
3093
+ __decorate([ApiProperty({
3094
+ type: "number",
3095
+ example: positionExample.chain_id
3096
+ })], PositionListItemResponse.prototype, "chain_id", void 0);
3097
+ __decorate([ApiProperty({
3098
+ type: "string",
3099
+ example: positionExample.contract
3100
+ })], PositionListItemResponse.prototype, "contract", void 0);
3101
+ __decorate([ApiProperty({
3102
+ type: "string",
3103
+ example: positionExample.user
3104
+ })], PositionListItemResponse.prototype, "user", void 0);
3105
+ __decorate([ApiProperty({
3106
+ type: "string",
3107
+ example: positionExample.reserved
3108
+ })], PositionListItemResponse.prototype, "reserved", void 0);
3109
+ __decorate([ApiProperty({
3110
+ type: "number",
3111
+ example: positionExample.block_number
3112
+ })], PositionListItemResponse.prototype, "block_number", void 0);
3113
+ var PositionListResponse = class extends SuccessResponse {};
3114
+ __decorate([ApiProperty({
3115
+ type: "string",
3116
+ nullable: true,
3117
+ example: offerCursorExample
3118
+ })], PositionListResponse.prototype, "cursor", void 0);
3119
+ __decorate([ApiProperty({
3120
+ type: () => [PositionListItemResponse],
3121
+ description: "User positions with reserved balances from active offers.",
3122
+ example: [positionExample]
3123
+ })], PositionListResponse.prototype, "data", void 0);
3124
+ var BookListResponse = class extends SuccessResponse {};
3125
+ __decorate([ApiProperty({
3126
+ type: "string",
3127
+ nullable: true,
3128
+ example: offerCursorExample
3129
+ })], BookListResponse.prototype, "cursor", void 0);
3130
+ __decorate([ApiProperty({
3131
+ type: () => [BookLevelResponse],
3132
+ description: "Aggregated book levels grouped by computed price."
3133
+ })], BookListResponse.prototype, "data", void 0);
3134
+ let BooksController = class BooksController$1 {
3135
+ async getBook() {}
3136
+ };
3137
+ __decorate([
3138
+ ApiOperation({
3139
+ methods: ["get"],
3140
+ path: "/v1/books/{obligationId}/{side}",
3141
+ summary: "Get aggregated book",
3142
+ description: "Returns aggregated book data for a given obligation and side. Offers are grouped by computed price with summed takeable amounts. Book levels are sorted by price (ascending for buy side, descending for sell side)."
3143
+ }),
3144
+ ApiParam({
3145
+ name: "obligationId",
3146
+ type: "string",
3147
+ example: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
3148
+ description: "Obligation id."
3149
+ }),
3150
+ ApiParam({
3151
+ name: "side",
3152
+ type: "string",
3153
+ enum: ["buy", "sell"],
3154
+ example: "buy",
3155
+ description: "Book side (buy or sell)."
3156
+ }),
3157
+ ApiQuery({
3158
+ name: "cursor",
3159
+ type: "string",
3160
+ example: offerCursorExample,
3161
+ description: "Pagination cursor in base64url-encoded format."
3162
+ }),
3163
+ ApiQuery({
3164
+ name: "limit",
3165
+ type: "number",
3166
+ example: 10,
3167
+ description: "Maximum number of price levels to return."
3168
+ }),
3169
+ ApiResponse({
3170
+ status: 200,
3171
+ description: "Success",
3172
+ type: BookListResponse
3173
+ })
3174
+ ], BooksController.prototype, "getBook", null);
3175
+ BooksController = __decorate([ApiTags("Markets"), ApiResponse({
3176
+ status: 400,
3177
+ description: "Bad Request",
3178
+ type: BadRequestResponse
3179
+ })], BooksController);
3180
+ let ValidateController = class ValidateController$1 {
3181
+ async validateOffers() {}
3182
+ };
3183
+ __decorate([
3184
+ ApiOperation({
3185
+ methods: ["post"],
3186
+ path: "/v1/validate",
3187
+ summary: "Validate offers",
3188
+ description: "Validates offers against router validation rules. Returns unsigned payload + root on success, or issues only on validation failure."
3189
+ }),
3190
+ ApiBody({ type: ValidateOffersRequest }),
3191
+ ApiResponse({
3192
+ status: 200,
3193
+ description: "Success",
3194
+ type: ValidationSuccessResponse
3195
+ }),
3196
+ ApiResponse({
3197
+ status: 200,
3198
+ description: "Validation issues",
3199
+ type: ValidationFailureResponse
3200
+ })
3201
+ ], ValidateController.prototype, "validateOffers", null);
3202
+ ValidateController = __decorate([ApiTags("Make"), ApiResponse({
3203
+ status: 400,
3204
+ description: "Bad Request",
3205
+ type: BadRequestResponse
3206
+ })], ValidateController);
3207
+ let OffersController = class OffersController$1 {
3208
+ async getOffers() {}
3209
+ };
3210
+ __decorate([
3211
+ ApiOperation({
3212
+ methods: ["get"],
3213
+ path: "/v1/offers",
3214
+ summary: "List all offers",
3215
+ description: "Returns offers. Provide either `obligation_id` + `side` (order book) or `maker` (by maker address)."
3216
+ }),
3217
+ ApiQuery({
3218
+ name: "side",
3219
+ type: "string",
3220
+ required: false,
3221
+ enum: ["buy", "sell"],
3222
+ example: "buy",
3223
+ description: "Side of the offer. Required when using obligation_id."
3224
+ }),
3225
+ ApiQuery({
3226
+ name: "obligation_id",
3227
+ type: "string",
3228
+ required: false,
3229
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234",
3230
+ description: "Obligation id used to filter offers. Required when not using maker."
3231
+ }),
3232
+ ApiQuery({
3233
+ name: "maker",
3234
+ type: "string",
3235
+ required: false,
3236
+ example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
3237
+ description: "Maker address to filter offers by. Alternative to obligation_id + side."
3238
+ }),
3239
+ ApiQuery({
3240
+ name: "cursor",
3241
+ type: "string",
3242
+ example: offerCursorExample,
3243
+ description: "Pagination cursor in base64url-encoded format."
3244
+ }),
3245
+ ApiQuery({
3246
+ name: "limit",
3247
+ type: "number",
3248
+ example: 10,
3249
+ description: "Maximum number of offers to return."
3250
+ }),
3251
+ ApiResponse({
3252
+ status: 200,
3253
+ description: "Success",
3254
+ type: OfferListResponse
3255
+ })
3256
+ ], OffersController.prototype, "getOffers", null);
3257
+ OffersController = __decorate([ApiTags("Markets"), ApiResponse({
3258
+ status: 400,
3259
+ description: "Bad Request",
3260
+ type: BadRequestResponse
3261
+ })], OffersController);
3262
+ let HealthController = class HealthController$1 {
3263
+ async getRouterStatus() {}
3264
+ async getCollectorsHealth() {}
3265
+ async getChainsHealth() {}
2759
3266
  };
2760
- var InvalidOfferError = class InvalidOfferError extends BaseError {
2761
- constructor(error) {
2762
- super("Invalid offer.", { cause: error });
2763
- _defineProperty(this, "name", "Offer.InvalidOfferError");
2764
- }
2765
- /**
2766
- * Formats ZodError issues into a human-readable string with line breaks.
2767
- * @example
2768
- * "- 'assets': too small, expected >= 0
2769
- * - 'start': must be before expiry"
2770
- */
2771
- static formatDetails(error) {
2772
- if (!(error instanceof z$1.ZodError)) return error.message;
2773
- return error.issues.map((issue) => {
2774
- return `'${issue.path.join(".")}': ${(issue.message.includes(":") ? issue.message.split(":")[1].trim() : issue.message.trim()).toLowerCase()}`;
2775
- }).join(". ");
2776
- }
2777
- /**
2778
- * Returns the formatted human-readable message.
2779
- */
2780
- get formattedMessage() {
2781
- return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
2782
- }
3267
+ __decorate([
3268
+ ApiOperation({
3269
+ methods: ["get"],
3270
+ path: "/v1/health",
3271
+ summary: "Retrieve global health",
3272
+ description: "Returns the aggregated status of the router."
3273
+ }),
3274
+ ApiQuery({
3275
+ name: "strict",
3276
+ type: "boolean",
3277
+ required: false,
3278
+ example: true,
3279
+ description: "Fail the request if initialization is incomplete."
3280
+ }),
3281
+ ApiResponse({
3282
+ status: 200,
3283
+ description: "Success",
3284
+ type: RouterStatusSuccessResponse
3285
+ })
3286
+ ], HealthController.prototype, "getRouterStatus", null);
3287
+ __decorate([
3288
+ ApiOperation({
3289
+ methods: ["get"],
3290
+ path: "/v1/health/collectors",
3291
+ summary: "Retrieve collectors health",
3292
+ description: "Returns the latest block numbers processed by collectors and their sync status."
3293
+ }),
3294
+ ApiQuery({
3295
+ name: "strict",
3296
+ type: "boolean",
3297
+ required: false,
3298
+ example: true,
3299
+ description: "Fail the request if initialization is incomplete."
3300
+ }),
3301
+ ApiResponse({
3302
+ status: 200,
3303
+ description: "Success",
3304
+ type: CollectorsHealthSuccessResponse
3305
+ })
3306
+ ], HealthController.prototype, "getCollectorsHealth", null);
3307
+ __decorate([
3308
+ ApiOperation({
3309
+ methods: ["get"],
3310
+ path: "/v1/health/chains",
3311
+ summary: "Retrieve chains health",
3312
+ description: "Returns the latest block that can be processed by collectors for each chain."
3313
+ }),
3314
+ ApiQuery({
3315
+ name: "strict",
3316
+ type: "boolean",
3317
+ required: false,
3318
+ example: true,
3319
+ description: "Fail the request if initialization is incomplete."
3320
+ }),
3321
+ ApiResponse({
3322
+ status: 200,
3323
+ description: "Success",
3324
+ type: ChainsHealthSuccessResponse
3325
+ })
3326
+ ], HealthController.prototype, "getChainsHealth", null);
3327
+ HealthController = __decorate([ApiTags("System")], HealthController);
3328
+ const maturitiesExample = {
3329
+ end_of_month: 1738335600,
3330
+ end_of_next_month: 1740754800
2783
3331
  };
2784
- var AccountNotSetError = class extends BaseError {
2785
- constructor() {
2786
- super("Account not set.");
2787
- _defineProperty(this, "name", "Offer.AccountNotSetError");
2788
- }
3332
+ const chainConfigExample = {
3333
+ chain_id: 505050505,
3334
+ contracts: { mempool: "0xD946246695A9259F3B33a78629026F61B3Ab40aF" },
3335
+ maturities: maturitiesExample
2789
3336
  };
2790
-
2791
- //#endregion
2792
- //#region src/core/Oracle.ts
2793
- var Oracle_exports = /* @__PURE__ */ __export({
2794
- Conversion: () => Conversion,
2795
- from: () => from$4
2796
- });
2797
- /**
2798
- * Create an Oracle from a plain object.
2799
- * @param data - The data to create the oracle from.
2800
- * @returns The created oracle.
2801
- */
2802
- function from$4(data) {
2803
- return {
2804
- chainId: data.chainId,
2805
- address: data.address.toLowerCase(),
2806
- price: data.price ? BigInt(data.price) : null,
2807
- blockNumber: data.blockNumber
2808
- };
2809
- }
2810
- let Conversion;
2811
- (function(_Conversion) {
2812
- function collateralToLoan(amount, params) {
2813
- return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
2814
- }
2815
- _Conversion.collateralToLoan = collateralToLoan;
2816
- function loanToCollateral(amount, params) {
2817
- if (params.price === 0n || params.lltv === 0n) return 0n;
2818
- return amount * 10n ** 36n / params.price * 10n ** 18n / params.lltv;
3337
+ var ConfigContractsResponse = class {};
3338
+ __decorate([ApiProperty({
3339
+ type: "string",
3340
+ example: chainConfigExample.contracts.mempool
3341
+ })], ConfigContractsResponse.prototype, "mempool", void 0);
3342
+ var MaturitiesResponse = class {};
3343
+ __decorate([ApiProperty({
3344
+ type: "number",
3345
+ description: "Unix timestamp for end of current month maturity (last Friday 15:00 UTC).",
3346
+ example: maturitiesExample.end_of_month
3347
+ })], MaturitiesResponse.prototype, "end_of_month", void 0);
3348
+ __decorate([ApiProperty({
3349
+ type: "number",
3350
+ description: "Unix timestamp for end of next month maturity (last Friday 15:00 UTC).",
3351
+ example: maturitiesExample.end_of_next_month
3352
+ })], MaturitiesResponse.prototype, "end_of_next_month", void 0);
3353
+ var ConfigDataResponse = class {};
3354
+ __decorate([ApiProperty({
3355
+ type: "number",
3356
+ example: chainConfigExample.chain_id
3357
+ })], ConfigDataResponse.prototype, "chain_id", void 0);
3358
+ __decorate([ApiProperty({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
3359
+ __decorate([ApiProperty({
3360
+ type: () => MaturitiesResponse,
3361
+ description: "Supported maturity timestamps. Offers must use one of these values.",
3362
+ example: chainConfigExample.maturities
3363
+ })], ConfigDataResponse.prototype, "maturities", void 0);
3364
+ var ConfigSuccessResponse = class extends SuccessResponse {};
3365
+ __decorate([ApiProperty({
3366
+ type: "string",
3367
+ nullable: true,
3368
+ example: null
3369
+ })], ConfigSuccessResponse.prototype, "cursor", void 0);
3370
+ __decorate([ApiProperty({
3371
+ type: () => [ConfigDataResponse],
3372
+ description: "Array of chain configurations for all indexed chains.",
3373
+ example: [chainConfigExample]
3374
+ })], ConfigSuccessResponse.prototype, "data", void 0);
3375
+ let ConfigController = class ConfigController$1 {
3376
+ async getConfig() {}
3377
+ };
3378
+ __decorate([ApiOperation({
3379
+ methods: ["get"],
3380
+ path: "/v1/config",
3381
+ summary: "Get router configuration",
3382
+ description: "Returns chain configurations including contract addresses and supported maturity timestamps."
3383
+ }), ApiResponse({
3384
+ status: 200,
3385
+ description: "Success",
3386
+ type: ConfigSuccessResponse
3387
+ })], ConfigController.prototype, "getConfig", null);
3388
+ ConfigController = __decorate([ApiTags("System")], ConfigController);
3389
+ let ObligationsController = class ObligationsController$1 {
3390
+ async getObligations() {}
3391
+ async getObligation() {}
3392
+ };
3393
+ __decorate([
3394
+ ApiOperation({
3395
+ methods: ["get"],
3396
+ path: "/v1/obligations",
3397
+ summary: "List all obligations",
3398
+ description: "Returns a list of obligations with their current best ask and bid. Obligations are sorted by their id in ascending order by default."
3399
+ }),
3400
+ ApiQuery({
3401
+ name: "cursor",
3402
+ type: "string",
3403
+ example: obligationCursorExample,
3404
+ description: "Obligation id cursor for pagination."
3405
+ }),
3406
+ ApiQuery({
3407
+ name: "limit",
3408
+ type: "number",
3409
+ example: 10,
3410
+ description: "Maximum number of obligations to return."
3411
+ }),
3412
+ ApiQuery({
3413
+ name: "chain",
3414
+ type: "number",
3415
+ required: false,
3416
+ example: 1,
3417
+ description: "Filter by chain ID."
3418
+ }),
3419
+ ApiQuery({
3420
+ name: "loan_token",
3421
+ type: "string",
3422
+ required: false,
3423
+ example: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
3424
+ description: "Filter by loan token address."
3425
+ }),
3426
+ ApiQuery({
3427
+ name: "collateral_token",
3428
+ type: "string",
3429
+ required: false,
3430
+ example: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
3431
+ description: "Filter by collateral token (matches any collateral in the obligation)."
3432
+ }),
3433
+ ApiQuery({
3434
+ name: "maturity",
3435
+ type: "number",
3436
+ required: false,
3437
+ example: 1761922800,
3438
+ description: "Filter by exact maturity timestamp (unix seconds)."
3439
+ }),
3440
+ ApiResponse({
3441
+ status: 200,
3442
+ description: "Success",
3443
+ type: ObligationListResponse
3444
+ })
3445
+ ], ObligationsController.prototype, "getObligations", null);
3446
+ __decorate([
3447
+ ApiOperation({
3448
+ methods: ["get"],
3449
+ path: "/v1/obligations/{obligationId}",
3450
+ summary: "Get an obligation",
3451
+ description: "Returns an obligation by its id."
3452
+ }),
3453
+ ApiParam({
3454
+ name: "obligationId",
3455
+ type: "string",
3456
+ example: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
3457
+ description: "Obligation id."
3458
+ }),
3459
+ ApiResponse({
3460
+ status: 200,
3461
+ description: "Success",
3462
+ type: ObligationSingleSuccessResponse
3463
+ })
3464
+ ], ObligationsController.prototype, "getObligation", null);
3465
+ ObligationsController = __decorate([ApiTags("Markets"), ApiResponse({
3466
+ status: 400,
3467
+ description: "Bad Request",
3468
+ type: BadRequestResponse
3469
+ })], ObligationsController);
3470
+ let UsersController = class UsersController$1 {
3471
+ async getUserPositions() {}
3472
+ };
3473
+ __decorate([
3474
+ ApiOperation({
3475
+ methods: ["get"],
3476
+ path: "/v1/users/{userAddress}/positions",
3477
+ summary: "Get user positions",
3478
+ description: "Returns positions for a user with reserved balance. The reserved balance is the amount locked by active offers (max lot upper - offset - consumed)."
3479
+ }),
3480
+ ApiParam({
3481
+ name: "userAddress",
3482
+ type: "string",
3483
+ example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
3484
+ description: "User address to get positions for."
3485
+ }),
3486
+ ApiQuery({
3487
+ name: "cursor",
3488
+ type: "string",
3489
+ example: offerCursorExample,
3490
+ description: "Pagination cursor in base64url-encoded format."
3491
+ }),
3492
+ ApiQuery({
3493
+ name: "limit",
3494
+ type: "number",
3495
+ example: 10,
3496
+ description: "Maximum number of positions to return."
3497
+ }),
3498
+ ApiResponse({
3499
+ status: 200,
3500
+ description: "Success",
3501
+ type: PositionListResponse
3502
+ })
3503
+ ], UsersController.prototype, "getUserPositions", null);
3504
+ UsersController = __decorate([ApiTags("Make"), ApiResponse({
3505
+ status: 400,
3506
+ description: "Bad Request",
3507
+ type: BadRequestResponse
3508
+ })], UsersController);
3509
+ const OpenApi = async (options = {}) => {
3510
+ const document = await generateDocument({
3511
+ controllers: [
3512
+ BooksController,
3513
+ ConfigController,
3514
+ OffersController,
3515
+ ObligationsController,
3516
+ HealthController,
3517
+ UsersController,
3518
+ ValidateController
3519
+ ],
3520
+ document: {
3521
+ openapi: "3.1.0",
3522
+ info: {
3523
+ title: "Router API",
3524
+ version: "1.0.0",
3525
+ description: "API for the Morpho Router"
3526
+ },
3527
+ servers: [{
3528
+ url: "https://router.morpho.dev",
3529
+ description: "Production server"
3530
+ }, {
3531
+ url: "http://localhost:7891",
3532
+ description: "Local development server"
3533
+ }],
3534
+ tags: [
3535
+ {
3536
+ name: "Markets",
3537
+ description: "Read-only endpoints to discover markets, order books and fetch current offers."
3538
+ },
3539
+ {
3540
+ name: "Make",
3541
+ description: "Utilities to ease making offers."
3542
+ },
3543
+ {
3544
+ name: "System",
3545
+ description: "Router configuration and health monitoring."
3546
+ }
3547
+ ]
3548
+ }
3549
+ });
3550
+ if (options.rules && options.rules.length > 0) {
3551
+ const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
3552
+ const validatePath = document.paths?.["/v1/validate"];
3553
+ if (validatePath && "post" in validatePath && validatePath.post) validatePath.post.description = `Validates offers against router validation rules. Returns unsigned payload + root on success, or issues only on validation failure.\n\n**Available validation rules:**\n${rulesDescription}`;
2819
3554
  }
2820
- _Conversion.loanToCollateral = loanToCollateral;
2821
- })(Conversion || (Conversion = {}));
3555
+ return document;
3556
+ };
2822
3557
 
2823
3558
  //#endregion
2824
- //#region src/core/Position.ts
2825
- var Position_exports = /* @__PURE__ */ __export({
2826
- Type: () => Type,
2827
- from: () => from$3
2828
- });
2829
- let Type = /* @__PURE__ */ function(Type$1) {
2830
- Type$1["ERC20"] = "erc20";
2831
- Type$1["VAULT_V1"] = "vault_v1";
2832
- return Type$1;
2833
- }({});
3559
+ //#region src/api/Schema/PositionResponse.ts
3560
+ var PositionResponse_exports = /* @__PURE__ */ __export({ from: () => from$1 });
2834
3561
  /**
2835
- * @constructor
2836
- * Creates a Position.
2837
- * @param parameters - {@link from.Parameters}
2838
- * @returns The created Position. {@link from.ReturnType}
3562
+ * Creates a `PositionResponse` from a `PositionWithReserved`.
3563
+ * @param position - {@link PositionWithReserved}
3564
+ * @returns The created `PositionResponse`. {@link PositionResponse}
2839
3565
  */
2840
- function from$3(parameters) {
3566
+ function from$1(position) {
2841
3567
  return {
2842
- chainId: parameters.chainId,
2843
- contract: parameters.contract.toLowerCase(),
2844
- user: parameters.user.toLowerCase(),
2845
- type: parameters.type,
2846
- balance: parameters.balance,
2847
- ...parameters.asset !== void 0 ? { asset: parameters.asset.toLowerCase() } : {},
2848
- blockNumber: parameters.blockNumber
3568
+ chain_id: position.chainId,
3569
+ contract: position.contract,
3570
+ user: position.user,
3571
+ reserved: position.reserved.toString(),
3572
+ block_number: position.blockNumber
2849
3573
  };
2850
3574
  }
2851
3575
 
2852
3576
  //#endregion
2853
- //#region src/core/Quote.ts
2854
- var Quote_exports = /* @__PURE__ */ __export({
2855
- InvalidQuoteError: () => InvalidQuoteError,
2856
- QuoteSchema: () => QuoteSchema,
2857
- from: () => from$2,
2858
- fromSnakeCase: () => fromSnakeCase,
2859
- random: () => random
2860
- });
2861
- const QuoteSchema = z$1.object({
2862
- obligationId: z$1.string().transform(transformHex),
2863
- ask: z$1.object({ rate: z$1.bigint({ coerce: true }).min(0n).max(maxUint256) }),
2864
- bid: z$1.object({ rate: z$1.bigint({ coerce: true }).min(0n).max(maxUint256) })
2865
- });
2866
- /**
2867
- * Creates a quote for a given obligation.
2868
- * @constructor
2869
- * @param parameters - {@link from.Parameters}
2870
- * @returns The created quote. {@link Quote}
2871
- * @throws If the quote is invalid. {@link InvalidQuoteError}
2872
- *
2873
- * @example
2874
- * ```ts
2875
- * const quote = Quote.from({ obligationId: "0x123", ask: { assets: 100n, rate: 100n }, bid: { assets: 100n, rate: 100n } });
2876
- * ```
2877
- */
2878
- function from$2(parameters) {
3577
+ //#region src/api/Schema/requests.ts
3578
+ const MAX_LIMIT = 100;
3579
+ const DEFAULT_LIMIT = 20;
3580
+ /** Validate cursor is a valid base64url-encoded JSON object.
3581
+ * Domain layer handles semantic validation of cursor fields. */
3582
+ function isValidBase64urlJson(val) {
2879
3583
  try {
2880
- const parsedQuote = QuoteSchema.parse(parameters);
2881
- return {
2882
- obligationId: parsedQuote.obligationId,
2883
- ask: parsedQuote.ask,
2884
- bid: parsedQuote.bid
2885
- };
2886
- } catch (error) {
2887
- throw new InvalidQuoteError(error);
3584
+ const decoded = Buffer.from(val, "base64url").toString("utf8");
3585
+ JSON.parse(decoded);
3586
+ return true;
3587
+ } catch {
3588
+ return false;
2888
3589
  }
2889
3590
  }
2890
- /**
2891
- * Creates a quote from a snake case object.
2892
- * @throws If the quote is invalid. {@link InvalidQuoteError}
2893
- * @param snake - {@link fromSnakeCase.Parameters}
2894
- * @returns The created quote. {@link fromSnakeCase.ReturnType}
2895
- */
2896
- function fromSnakeCase(snake) {
2897
- return from$2(fromSnakeCase$3(snake));
2898
- }
2899
- /**
2900
- * Generates a random quote.
2901
- * @returns A randomly generated quote. {@link random.ReturnType}
2902
- *
2903
- * @example
2904
- * ```ts
2905
- * const quote = Quote.random();
2906
- * ```
2907
- */
2908
- function random() {
2909
- return from$2({
2910
- obligationId: id(random$2()),
2911
- ask: { rate: BigInt(Math.floor(Math.random() * 1e6)) },
2912
- bid: { rate: BigInt(Math.floor(Math.random() * 1e6)) }
3591
+ const PaginationQueryParams = z$1.object({
3592
+ cursor: z$1.string().optional().refine((val) => {
3593
+ if (!val) return true;
3594
+ return isValidBase64urlJson(val);
3595
+ }, { message: "Invalid cursor format. Must be a valid base64url-encoded cursor object" }).meta({
3596
+ description: "Pagination cursor in base64url-encoded format",
3597
+ example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
3598
+ }),
3599
+ limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT).meta({
3600
+ description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
3601
+ example: 10
3602
+ })
3603
+ });
3604
+ const GetOffersQueryParams = z$1.object({
3605
+ ...PaginationQueryParams.shape,
3606
+ side: z$1.enum(["buy", "sell"]).optional().meta({
3607
+ description: "Side of the offer. Required when using obligation_id.",
3608
+ example: "buy"
3609
+ }),
3610
+ obligation_id: z$1.string().regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).optional().meta({
3611
+ description: "Offers obligation id. Required when not using maker.",
3612
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
3613
+ }),
3614
+ maker: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Maker must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).optional().meta({
3615
+ description: "Maker address to filter offers by. Alternative to obligation_id + side.",
3616
+ example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
3617
+ })
3618
+ }).superRefine((val, ctx) => {
3619
+ const hasObligation = val.obligation_id !== void 0;
3620
+ const hasSide = val.side !== void 0;
3621
+ const hasMaker = val.maker !== void 0;
3622
+ if (hasMaker && (hasObligation || hasSide)) {
3623
+ ctx.addIssue({
3624
+ code: "custom",
3625
+ message: "Cannot use both maker and obligation_id/side parameters"
3626
+ });
3627
+ return;
3628
+ }
3629
+ if (hasMaker) return;
3630
+ if (!hasObligation || !hasSide) ctx.addIssue({
3631
+ code: "custom",
3632
+ message: "Must provide either maker or both obligation_id and side"
2913
3633
  });
2914
- }
2915
- var InvalidQuoteError = class extends BaseError {
2916
- constructor(error) {
2917
- super("Invalid quote.", { cause: error });
2918
- _defineProperty(this, "name", "Quote.InvalidQuoteError");
3634
+ });
3635
+ const GetObligationsQueryParams = z$1.object({
3636
+ ...PaginationQueryParams.shape,
3637
+ cursor: z$1.string().optional().meta({
3638
+ description: "Obligation id cursor",
3639
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
3640
+ }),
3641
+ chain: z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).optional().meta({
3642
+ description: "Filter by chain ID",
3643
+ example: "1"
3644
+ }),
3645
+ loan_token: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Loan token must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).optional().meta({
3646
+ description: "Filter by loan token address",
3647
+ example: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078"
3648
+ }),
3649
+ collateral_token: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Collateral token must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).optional().meta({
3650
+ description: "Filter by collateral token (matches any collateral in the obligation)",
3651
+ example: "0x34Cf890dB685FC536E05652FB41f02090c3fb751"
3652
+ }),
3653
+ maturity: z$1.string().regex(/^[1-9]\d*$/, { message: "Maturity must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).optional().meta({
3654
+ description: "Filter by exact maturity timestamp (unix seconds)",
3655
+ example: "1761922800"
3656
+ })
3657
+ });
3658
+ const GetObligationParams = z$1.object({ obligation_id: z$1.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({
3659
+ description: "Obligation id",
3660
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
3661
+ }) });
3662
+ /** Validate a book cursor format: {side, lastPrice, offersCursor} */
3663
+ function isValidBookCursor(cursorString) {
3664
+ const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
3665
+ try {
3666
+ const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
3667
+ return (v?.side === "buy" || v?.side === "sell") && isNumericString(v?.lastPrice) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
3668
+ } catch {
3669
+ return false;
2919
3670
  }
3671
+ }
3672
+ const BookPaginationQueryParams = z$1.object({
3673
+ cursor: z$1.string().optional().refine((value) => {
3674
+ if (!value) return true;
3675
+ return isValidBookCursor(value);
3676
+ }, { message: "Invalid cursor format. Must be a valid base64url-encoded book cursor object" }).meta({
3677
+ description: "Pagination cursor in base64url-encoded format for book levels",
3678
+ example: "eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ"
3679
+ }),
3680
+ limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT).meta({
3681
+ description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT}`,
3682
+ example: 10
3683
+ })
3684
+ });
3685
+ const HealthQueryParams = z$1.object({ strict: z$1.enum([
3686
+ "true",
3687
+ "false",
3688
+ "1",
3689
+ "0"
3690
+ ]).transform((value) => value === "true" || value === "1").optional().meta({
3691
+ description: "Enable strict mode to fail health checks when initialization is incomplete.",
3692
+ example: "true"
3693
+ }) });
3694
+ const GetBookParams = z$1.object({
3695
+ ...BookPaginationQueryParams.shape,
3696
+ obligation_id: z$1.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({
3697
+ description: "Obligation id",
3698
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
3699
+ }),
3700
+ side: z$1.enum(["buy", "sell"]).meta({
3701
+ description: "Side of the book (buy or sell).",
3702
+ example: "buy"
3703
+ })
3704
+ });
3705
+ const ValidateOffersBody = z$1.object({ offers: z$1.array(z$1.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
3706
+ const GetUserPositionsParams = z$1.object({
3707
+ ...PaginationQueryParams.shape,
3708
+ user_address: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
3709
+ description: "User address to get positions for",
3710
+ example: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
3711
+ })
3712
+ });
3713
+ const schemas = {
3714
+ get_health: HealthQueryParams,
3715
+ get_health_collectors: HealthQueryParams,
3716
+ get_health_chains: HealthQueryParams,
3717
+ get_offers: GetOffersQueryParams,
3718
+ get_obligations: GetObligationsQueryParams,
3719
+ get_obligation: GetObligationParams,
3720
+ get_book: GetBookParams,
3721
+ validate_offers: ValidateOffersBody,
3722
+ get_user_positions: GetUserPositionsParams
2920
3723
  };
2921
-
2922
- //#endregion
2923
- //#region src/core/Transfer.ts
2924
- var Transfer_exports = /* @__PURE__ */ __export({ from: () => from$1 });
2925
- /**
2926
- * @constructor
2927
- *
2928
- * Creates a {@link Transfer}.
2929
- * @param parameters - {@link from.Parameters}
2930
- * @returns The created Transfer. {@link from.ReturnType}
2931
- *
2932
- * @example
2933
- * ```ts
2934
- * const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
2935
- * ```
2936
- */
2937
- function from$1(parameters) {
2938
- return {
2939
- id: parameters.id,
2940
- chainId: parameters.chainId,
2941
- contract: parameters.contract.toLowerCase(),
2942
- from: parameters.from.toLowerCase(),
2943
- to: parameters.to.toLowerCase(),
2944
- value: parameters.value,
2945
- blockNumber: parameters.blockNumber
2946
- };
3724
+ function parse(action, query) {
3725
+ return schemas[action].parse(query);
3726
+ }
3727
+ function safeParse(action, query, error) {
3728
+ return schemas[action].safeParse(query, { error });
2947
3729
  }
2948
3730
 
2949
3731
  //#endregion
2950
- //#region src/core/types.ts
2951
- const BrandTypeId = Symbol.for("mempool/Brand");
3732
+ //#region src/api/Schema/index.ts
3733
+ var Schema_exports = /* @__PURE__ */ __export({
3734
+ BookResponse: () => BookResponse_exports,
3735
+ BooksController: () => BooksController,
3736
+ ChainHealth: () => ChainHealth,
3737
+ ChainsHealthResponse: () => ChainsHealthResponse,
3738
+ CollectorHealth: () => CollectorHealth,
3739
+ CollectorsHealthResponse: () => CollectorsHealthResponse,
3740
+ ConfigController: () => ConfigController,
3741
+ HealthController: () => HealthController,
3742
+ ObligationResponse: () => ObligationResponse_exports,
3743
+ ObligationsController: () => ObligationsController,
3744
+ OfferResponse: () => OfferResponse_exports,
3745
+ OffersController: () => OffersController,
3746
+ OpenApi: () => OpenApi,
3747
+ PositionResponse: () => PositionResponse_exports,
3748
+ RouterStatusResponse: () => RouterStatusResponse,
3749
+ UsersController: () => UsersController,
3750
+ ValidateController: () => ValidateController,
3751
+ parse: () => parse,
3752
+ safeParse: () => safeParse
3753
+ });
2952
3754
 
2953
3755
  //#endregion
2954
3756
  //#region src/client/Client.ts
@@ -3009,24 +3811,40 @@ async function getOffers(apiClient, parameters) {
3009
3811
  throw new HttpGetApiFailedError(`GET request returned ${response.status}`, { details: JSON.stringify(error) });
3010
3812
  }
3011
3813
  const offers = data?.data.map((item) => {
3012
- const { signature, ...rest } = item;
3013
- return fromSnakeCase$1({
3014
- ...rest,
3015
- offering: item.offering,
3016
- maturity: from$8(item.maturity),
3017
- loan_token: item.loan_token,
3018
- collaterals: item.collaterals.map((collateral) => ({
3019
- asset: collateral.asset,
3020
- oracle: collateral.oracle,
3021
- lltv: collateral.lltv
3022
- })),
3023
- callback: {
3024
- ...item.callback,
3025
- address: item.callback.address,
3026
- data: item.callback.data
3027
- },
3028
- ...signature !== null ? { signature: item.signature } : void 0
3029
- });
3814
+ const { root, proof, signature, offer: offerData } = item;
3815
+ return {
3816
+ ...fromSnakeCase$1({
3817
+ maker: offerData.maker,
3818
+ assets: offerData.assets,
3819
+ obligation_units: offerData.obligation_units,
3820
+ obligation_shares: offerData.obligation_shares,
3821
+ price: offerData.price,
3822
+ maturity: from$10(offerData.obligation.maturity),
3823
+ expiry: offerData.expiry,
3824
+ start: offerData.start,
3825
+ group: offerData.group,
3826
+ session: offerData.session,
3827
+ buy: offerData.buy,
3828
+ chain_id: item.chain_id,
3829
+ loan_token: offerData.obligation.loan_token,
3830
+ collaterals: offerData.obligation.collaterals.map((collateral) => ({
3831
+ asset: collateral.token,
3832
+ oracle: collateral.oracle,
3833
+ lltv: collateral.lltv
3834
+ })),
3835
+ callback: {
3836
+ address: offerData.callback,
3837
+ data: offerData.callback_data
3838
+ }
3839
+ }),
3840
+ hash: item.offer_hash,
3841
+ consumed: BigInt(item.consumed),
3842
+ takeable: BigInt(item.takeable),
3843
+ blockNumber: Number(item.block_number),
3844
+ root: root || void 0,
3845
+ proof: proof || void 0,
3846
+ signature: signature ? signature : void 0
3847
+ };
3030
3848
  }) ?? [];
3031
3849
  return {
3032
3850
  cursor: data?.cursor ?? null,
@@ -3036,7 +3854,11 @@ async function getOffers(apiClient, parameters) {
3036
3854
  async function getObligations(apiClient, parameters) {
3037
3855
  const { data, error, response } = await apiClient.GET("/v1/obligations", { params: { query: {
3038
3856
  cursor: parameters?.cursor,
3039
- limit: parameters?.limit
3857
+ limit: parameters?.limit,
3858
+ chain: parameters?.chainId,
3859
+ loan_token: parameters?.loanToken,
3860
+ collateral_token: parameters?.collateralToken,
3861
+ maturity: parameters?.maturity
3040
3862
  } } });
3041
3863
  if (error !== void 0) {
3042
3864
  switch (response.status) {
@@ -3051,11 +3873,11 @@ async function getObligations(apiClient, parameters) {
3051
3873
  chain_id: item.chain_id,
3052
3874
  loan_token: item.loan_token,
3053
3875
  collaterals: item.collaterals.map((collateral) => ({
3054
- asset: collateral.asset,
3876
+ asset: collateral.token,
3055
3877
  oracle: collateral.oracle,
3056
3878
  lltv: collateral.lltv
3057
3879
  })),
3058
- maturity: from$8(item.maturity)
3880
+ maturity: from$10(item.maturity)
3059
3881
  });
3060
3882
  const { obligationId: _, ...returned } = {
3061
3883
  id: () => id(obligation),
@@ -3217,8 +4039,8 @@ function getCallback(chain, type) {
3217
4039
  * @param address - Callback contract address
3218
4040
  * @returns The callback type when found, otherwise undefined
3219
4041
  */
3220
- function getCallbackType(chain, address) {
3221
- return configs[chain].callbacks?.find((c) => c.type !== CallbackType.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
4042
+ function getCallbackType(chain, address$1) {
4043
+ return configs[chain].callbacks?.find((c) => c.type !== CallbackType.BuyWithEmptyCallback && c.addresses.includes(address$1?.toLowerCase()))?.type;
3222
4044
  }
3223
4045
  /**
3224
4046
  * Returns the callback addresses for a given chain and callback type, if it exists.
@@ -3348,9 +4170,11 @@ function create(parameters) {
3348
4170
  //#endregion
3349
4171
  //#region src/gatekeeper/Rules.ts
3350
4172
  var Rules_exports = /* @__PURE__ */ __export({
4173
+ amountMutualExclusivity: () => amountMutualExclusivity,
3351
4174
  callback: () => callback,
3352
4175
  chains: () => chains,
3353
4176
  maturity: () => maturity,
4177
+ sameMaker: () => sameMaker,
3354
4178
  token: () => token,
3355
4179
  validity: () => validity
3356
4180
  });
@@ -3466,7 +4290,7 @@ const chains = ({ chains: chains$2 }) => single("chain_ids", `Validates that off
3466
4290
  if (!allowedChainIds.some((id$1) => id$1 === offer.chainId)) return { message: `Chain ID ${offer.chainId} is not in the allowed chains (${allowedChainIds.join(", ")})` };
3467
4291
  });
3468
4292
  const maturity = ({ maturities }) => single("maturity", `Validates that offer maturity is one of: [${maturities.join(", ")}]`, (offer) => {
3469
- const allowedMaturities = maturities.map((m) => from$8(m));
4293
+ const allowedMaturities = maturities.map((m) => from$10(m));
3470
4294
  if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be end of current month (${allowedMaturities[0]}) or end of next month (${allowedMaturities[1]}). Got: ${offer.maturity}` };
3471
4295
  });
3472
4296
  const callback = ({ callbacks, allowedAddresses }) => single("callback", `Validates callbacks: buy empty callback is ${callbacks.includes(CallbackType.BuyWithEmptyCallback) ? "allowed" : "not allowed"}; sell offers must use a non-empty callback; non-empty callbacks must target one of [${allowedAddresses.map((a) => a.toLowerCase()).join(", ")}]`, (offer) => {
@@ -3477,32 +4301,64 @@ const callback = ({ callbacks, allowedAddresses }) => single("callback", `Valida
3477
4301
  }
3478
4302
  });
3479
4303
  /**
3480
- * A validation rule that checks if the offer's token is allowed.
3481
- * @param offer - The offer to validate.
4304
+ * A validation rule that checks if the offer's tokens are allowed for its chain.
4305
+ * @param assetsByChainId - Allowed assets indexed by chain id.
3482
4306
  * @returns The issue that was found. If the offer is valid, this will be undefined.
3483
4307
  */
3484
- const token = ({ assets: assets$1 }) => single("token", "Validates that offer loan token and collateral tokens are in the allowed assets list", (offer) => {
3485
- const allowedAssets = assets$1?.map((asset) => asset.toLowerCase());
3486
- if (!allowedAssets || allowedAssets.length === 0) return { message: "No allowed assets" };
4308
+ const token = ({ assetsByChainId }) => single("token", "Validates that offer loan token and collateral tokens are in the allowed assets list for the offer chain", (offer) => {
4309
+ const allowedAssets = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
4310
+ if (!allowedAssets || allowedAssets.length === 0) return { message: `No allowed assets for chain ${offer.chainId}` };
3487
4311
  if (!allowedAssets.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
3488
4312
  if (offer.collaterals.some((collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()))) return { message: "Collateral is not allowed" };
3489
4313
  });
4314
+ /**
4315
+ * A batch validation rule that ensures all offers in a tree have the same maker address.
4316
+ * Returns an issue only for the first non-conforming offer.
4317
+ * This rule is signing-agnostic; signer verification is handled at the collector level.
4318
+ */
4319
+ const sameMaker = () => batch$1("mixed_maker", "Validates that all offers in a batch have the same maker address", (offers) => {
4320
+ const issues = /* @__PURE__ */ new Map();
4321
+ if (offers.length === 0) return issues;
4322
+ const firstMaker = offers[0].maker.toLowerCase();
4323
+ for (let i = 1; i < offers.length; i++) {
4324
+ const offer = offers[i];
4325
+ if (offer.maker.toLowerCase() !== firstMaker) {
4326
+ issues.set(i, { message: `Offer has different maker ${offer.maker} than first offer ${offers[0].maker}` });
4327
+ return issues;
4328
+ }
4329
+ }
4330
+ return issues;
4331
+ });
4332
+ /**
4333
+ * A validation rule that ensures mutual exclusivity of offer amount fields.
4334
+ * At most one of (assets, obligationUnits, obligationShares) can be non-zero.
4335
+ * Matches contract requirement: `atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)`.
4336
+ */
4337
+ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Validates that at most one of (assets, obligationUnits, obligationShares) is non-zero", (offer) => {
4338
+ if (!atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)) return { message: "Inconsistent offer input: at most one of (assets, obligationUnits, obligationShares) must be non-zero" };
4339
+ });
3490
4340
 
3491
4341
  //#endregion
3492
4342
  //#region src/gatekeeper/morphoRules.ts
3493
- const morphoRules = (chains$2) => [
3494
- chains({ chains: chains$2 }),
3495
- maturity({ maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth] }),
3496
- callback({
3497
- callbacks: [
3498
- CallbackType.BuyWithEmptyCallback,
3499
- CallbackType.BuyVaultV1Callback,
3500
- CallbackType.SellERC20Callback
3501
- ],
3502
- allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
3503
- }),
3504
- token({ assets: chains$2.flatMap((c) => assets[c.id.toString()] ?? []) })
3505
- ];
4343
+ const morphoRules = (chains$2) => {
4344
+ const assetsByChainId = {};
4345
+ for (const chain of chains$2) assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
4346
+ return [
4347
+ sameMaker(),
4348
+ amountMutualExclusivity(),
4349
+ chains({ chains: chains$2 }),
4350
+ maturity({ maturities: [MaturityType.EndOfMonth, MaturityType.EndOfNextMonth] }),
4351
+ callback({
4352
+ callbacks: [
4353
+ CallbackType.BuyWithEmptyCallback,
4354
+ CallbackType.BuyVaultV1Callback,
4355
+ CallbackType.SellERC20Callback
4356
+ ],
4357
+ allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
4358
+ }),
4359
+ token({ assetsByChainId })
4360
+ ];
4361
+ };
3506
4362
 
3507
4363
  //#endregion
3508
4364
  //#region src/mempool/MempoolEVMClient.ts
@@ -3528,25 +4384,27 @@ function from(parameters) {
3528
4384
  */
3529
4385
  async function add(config, offers) {
3530
4386
  if (!config.client.account) throw new WalletAccountNotSetError();
3531
- const tree = from$6(offers.map((o) => from$5(o)));
4387
+ const tree = from$8(offers.map((o) => from$7(o)));
3532
4388
  const chainId = await getChainId(config.client);
3533
4389
  for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
4390
+ const signature = await sign(tree.offers, config.client);
4391
+ const encoded = await encode$1(tree, signature);
3534
4392
  try {
3535
4393
  return await config.client.sendTransaction({
3536
4394
  chain: config.client.chain,
3537
4395
  account: config.client.account,
3538
4396
  to: config.mempoolAddress,
3539
- data: encode$1(tree)
4397
+ data: encoded
3540
4398
  });
3541
4399
  } catch (error) {
3542
4400
  throw new ViemClientError(error instanceof Error ? error.message : "Unknown error");
3543
4401
  }
3544
4402
  }
3545
4403
  async function* get(config, parameters) {
3546
- const { loanToken, blockNumberGte, blockNumberLte, order: order$1 = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE } = {} } = parameters || {};
4404
+ const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE } = {} } = parameters || {};
3547
4405
  yield* streamOffers(config, {
3548
4406
  loanToken,
3549
- order: order$1,
4407
+ order,
3550
4408
  blockNumberGte,
3551
4409
  blockNumberLte,
3552
4410
  options: {
@@ -3568,7 +4426,7 @@ const getChainId = async (client) => {
3568
4426
  return chainId;
3569
4427
  };
3570
4428
  async function* streamOffers(config, parameters) {
3571
- const { loanToken, blockNumberGte, blockNumberLte, order: order$1 = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
4429
+ const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
3572
4430
  const stream = streamLogs({
3573
4431
  client: config.client.extend(publicActions),
3574
4432
  contractAddress: config.mempoolAddress,
@@ -3585,13 +4443,13 @@ async function* streamOffers(config, parameters) {
3585
4443
  },
3586
4444
  blockNumberGte,
3587
4445
  blockNumberLte,
3588
- order: order$1,
4446
+ order,
3589
4447
  options: {
3590
4448
  maxBatchSize,
3591
4449
  blockWindow
3592
4450
  }
3593
4451
  });
3594
- let blockNumber = order$1 === "asc" ? blockNumberGte : blockNumberLte;
4452
+ let blockNumber = order === "asc" ? blockNumberGte : blockNumberLte;
3595
4453
  for await (const { logs, blockNumber: newBlockNumber } of stream) {
3596
4454
  blockNumber = newBlockNumber;
3597
4455
  if (logs.length === 0) continue;
@@ -3600,13 +4458,10 @@ async function* streamOffers(config, parameters) {
3600
4458
  if (!log) continue;
3601
4459
  const [payload] = decodeAbiParameters([{ type: "bytes" }], log.data);
3602
4460
  try {
3603
- const tree = decode$1(payload);
4461
+ const { tree } = await decode$1(payload);
3604
4462
  for (const offer of tree.offers) {
3605
4463
  if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
3606
- offers.push({
3607
- ...offer,
3608
- blockNumber: Number(log.blockNumber)
3609
- });
4464
+ offers.push(offer);
3610
4465
  }
3611
4466
  } catch (_) {}
3612
4467
  }
@@ -3685,6 +4540,20 @@ async function batchMulticall(parameters) {
3685
4540
  return results;
3686
4541
  }
3687
4542
 
4543
+ //#endregion
4544
+ //#region src/utils/Group.ts
4545
+ var Group_exports = /* @__PURE__ */ __export({ fromNumber: () => fromNumber });
4546
+ /**
4547
+ * Creates a bytes32 group identifier from a number.
4548
+ * @param n - A non-negative integer.
4549
+ * @throws {Error} If n is negative or not an integer.
4550
+ */
4551
+ const fromNumber = (n) => {
4552
+ if (!Number.isInteger(n)) throw new Error(`Group.fromNumber: expected integer, got ${n}`);
4553
+ if (n < 0) throw new Error(`Group.fromNumber: expected non-negative, got ${n}`);
4554
+ return pad(`0x${n.toString(16)}`, { size: 32 });
4555
+ };
4556
+
3688
4557
  //#endregion
3689
4558
  //#region src/utils/lazy.ts
3690
4559
  /**
@@ -3769,8 +4638,11 @@ function max() {
3769
4638
  //#region src/utils/index.ts
3770
4639
  var utils_exports = /* @__PURE__ */ __export({
3771
4640
  BaseError: () => BaseError,
4641
+ Group: () => Group_exports,
4642
+ Random: () => Random_exports,
3772
4643
  ReorgError: () => ReorgError,
3773
4644
  Time: () => time_exports,
4645
+ atMostOneNonZero: () => atMostOneNonZero,
3774
4646
  batch: () => batch,
3775
4647
  batchMulticall: () => batchMulticall,
3776
4648
  fromSnakeCase: () => fromSnakeCase$3,
@@ -3785,5 +4657,5 @@ var utils_exports = /* @__PURE__ */ __export({
3785
4657
  });
3786
4658
 
3787
4659
  //#endregion
3788
- export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, Collateral_exports as Collateral, Cursor_exports as Cursor, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, GateConfig_exports as GateConfig, Gatekeeper_exports as Gatekeeper, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Oracle_exports as Oracle, Position_exports as Position, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports as RouterClient, Rules_exports as Rules, time_exports as Time, Transfer_exports as Transfer, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation, morphoRules };
4660
+ export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainRegistry_exports as ChainRegistry, Collateral_exports as Collateral, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, GateConfig_exports as GateConfig, Gatekeeper_exports as Gatekeeper, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Oracle_exports as Oracle, Position_exports as Position, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports as RouterClient, Rules_exports as Rules, time_exports as Time, Transfer_exports as Transfer, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation, morphoRules };
3789
4661
  //# sourceMappingURL=index.browser.mjs.map