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