@morpho-dev/router 0.11.0 → 0.12.1

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 (48) hide show
  1. package/README.md +20 -5
  2. package/dist/cli.js +12198 -6809
  3. package/dist/drizzle/migrations/0034_chain-checkpoints.sql +1 -0
  4. package/dist/drizzle/migrations/0035_chain-tip-hash-cas.sql +1 -0
  5. package/dist/drizzle/migrations/0036_pending-links.sql +22 -0
  6. package/dist/drizzle/migrations/0037_chain-finalized-anchor.sql +2 -0
  7. package/dist/drizzle/migrations/0038_add-obligation-rcf-threshold.sql +2 -0
  8. package/dist/drizzle/migrations/0039_add-offers-composite-indexes.sql +2 -0
  9. package/dist/drizzle/migrations/0040_drop-redundant-offers-indexes.sql +2 -0
  10. package/dist/drizzle/migrations/0041_add-group-winner-expression-index.sql +10 -0
  11. package/dist/drizzle/migrations/0042_contract-sync-v1.14.sql +284 -0
  12. package/dist/drizzle/migrations/0043_add-obligation-side-tick-index.sql +1 -0
  13. package/dist/drizzle/migrations/0044_index-audit-cleanup.sql +27 -0
  14. package/dist/drizzle/migrations/0045_add-lots-offsets-availability-indexes.sql +5 -0
  15. package/dist/drizzle/migrations/0046_add-offers-active-tick-index.sql +1 -0
  16. package/dist/drizzle/migrations/0047_add-offers-book-winners-index.sql +1 -0
  17. package/dist/drizzle/migrations/0048_covering-indexes-for-winners-queries.sql +34 -0
  18. package/dist/drizzle/migrations/0049_contract-sync-v1.15.sql +305 -0
  19. package/dist/drizzle/migrations/0050_contract-sync-v1.16.sql +305 -0
  20. package/dist/drizzle/migrations/meta/0036_snapshot.json +1864 -0
  21. package/dist/drizzle/migrations/meta/0037_snapshot.json +1876 -0
  22. package/dist/drizzle/migrations/meta/0038_snapshot.json +1882 -0
  23. package/dist/drizzle/migrations/meta/0039_snapshot.json +1960 -0
  24. package/dist/drizzle/migrations/meta/0040_snapshot.json +1912 -0
  25. package/dist/drizzle/migrations/meta/0041_snapshot.json +1912 -0
  26. package/dist/drizzle/migrations/meta/0042_snapshot.json +1882 -0
  27. package/dist/drizzle/migrations/meta/0043_snapshot.json +1909 -0
  28. package/dist/drizzle/migrations/meta/0044_snapshot.json +1853 -0
  29. package/dist/drizzle/migrations/meta/0045_snapshot.json +1921 -0
  30. package/dist/drizzle/migrations/meta/0046_snapshot.json +1966 -0
  31. package/dist/drizzle/migrations/meta/0047_snapshot.json +2005 -0
  32. package/dist/drizzle/migrations/meta/0048_snapshot.json +2035 -0
  33. package/dist/drizzle/migrations/meta/0049_snapshot.json +2035 -0
  34. package/dist/drizzle/migrations/meta/0050_snapshot.json +2035 -0
  35. package/dist/drizzle/migrations/meta/_journal.json +119 -0
  36. package/dist/evm/bytecode/morpho.txt +1 -1
  37. package/dist/index.browser.d.mts +611 -282
  38. package/dist/index.browser.d.mts.map +1 -1
  39. package/dist/index.browser.mjs +735 -448
  40. package/dist/index.browser.mjs.map +1 -1
  41. package/dist/index.node.d.mts +1525 -614
  42. package/dist/index.node.d.mts.map +1 -1
  43. package/dist/index.node.mjs +9493 -5238
  44. package/dist/index.node.mjs.map +1 -1
  45. package/dist/server-DNFuP89-.js +9573 -0
  46. package/dist/server.js +9617 -0
  47. package/docs/integrator.md +14 -24
  48. package/package.json +7 -4
@@ -8,10 +8,10 @@ import createOpenApiFetchClient from "openapi-fetch";
8
8
  import { bytesToHex, concatHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, publicActions, recoverAddress, zeroAddress } from "viem";
9
9
  import { getBlockNumber, getLogs, multicall } from "viem/actions";
10
10
  import { anvil, base, mainnet } from "viem/chains";
11
- import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
12
- import { gzip, ungzip } from "pako";
11
+ import { SimpleMerkleTree } from "@openzeppelin/merkle-tree";
12
+ import { Inflate, gzip } from "pako";
13
13
  import { context, propagation } from "@opentelemetry/api";
14
- import "drizzle-orm";
14
+ import { sql } from "drizzle-orm";
15
15
  import { bigint, boolean, foreignKey, index, integer, numeric, pgSchema, primaryKey, serial, text, timestamp, uniqueIndex, varchar } from "drizzle-orm/pg-core";
16
16
 
17
17
  //#region src/utils/Errors.ts
@@ -77,8 +77,10 @@ var Tick_exports = /* @__PURE__ */ __exportAll({
77
77
  InvalidTickError: () => InvalidTickError,
78
78
  MAX_PRICE: () => MAX_PRICE,
79
79
  TICK_RANGE: () => TICK_RANGE,
80
+ assetsToUnits: () => assetsToUnits,
80
81
  priceToTick: () => priceToTick,
81
- tickToPrice: () => tickToPrice
82
+ tickToPrice: () => tickToPrice,
83
+ unitsToAssets: () => unitsToAssets
82
84
  });
83
85
  /** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
84
86
  const LN_ONE_PLUS_DELTA = 24692612590371501n;
@@ -136,6 +138,81 @@ function assertTick(tick) {
136
138
  function assertPrice(price) {
137
139
  if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
138
140
  }
141
+ /**
142
+ * Converts units into maker-side assets using the raw tick price surface.
143
+ * This is the public forward conversion used by the router for lot sizing and other maker-facing capacity math.
144
+ * - `buy = true` -> `floor(units * price / WAD)`
145
+ * - `buy = false` -> `ceil(units * price / WAD)`
146
+ * @param units - The units to convert.
147
+ * @param tick - The offer tick.
148
+ * @param buy - Whether the maker side of the offer is buy (`true`) or sell (`false`).
149
+ * @returns The equivalent amount in maker-side assets.
150
+ */
151
+ function unitsToAssets(units, tick, buy) {
152
+ const price = tickToPrice(tick);
153
+ return buy ? unitsToFloorAssets(units, price) : unitsToCeilAssets(units, price);
154
+ }
155
+ /**
156
+ * Converts a maker-side asset cap into a safe units cap using the raw tick price.
157
+ * Buy offers use the max-safe inverse of `floor(units * price / WAD)`.
158
+ * Sell offers use the max-safe inverse of `ceil(units * price / WAD)`.
159
+ * The result is clamped to the remaining offer size because the asset cap may have been rounded before inversion.
160
+ * Zero integer asset caps can still admit positive units on floor-rounded sub-WAD buy ticks, and tick=0 keeps the
161
+ * whole remaining interval safe because the raw maker-asset surface stays at zero.
162
+ * @param assets - The integer maker-side asset cap.
163
+ * @param tick - The offer tick.
164
+ * @param buy - Whether the maker side of the offer is buy (`true`) or sell (`false`).
165
+ * @param remainingUnits - The maximum units still available on the offer.
166
+ * @returns The greatest safe units amount under the maker-side raw-price surface.
167
+ */
168
+ function assetsToUnits(assets, tick, buy, remainingUnits) {
169
+ if (remainingUnits <= 0n) return 0n;
170
+ if (assets < 0n) return 0n;
171
+ const price = tickToPrice(tick);
172
+ if (price === 0n) return remainingUnits;
173
+ const units = buy ? floorAssetsToUnits(assets, price) : ceilAssetsToUnits(assets, price);
174
+ return units > remainingUnits ? remainingUnits : units;
175
+ }
176
+ /**
177
+ * Forward conversion for raw-price floor surfaces.
178
+ * This matches buy-side maker assets and the legacy floor-only helper.
179
+ * @param units - The units to convert.
180
+ * @param price - The raw tick price.
181
+ * @returns The floor-rounded maker-side assets.
182
+ */
183
+ function unitsToFloorAssets(units, price) {
184
+ return units * price / WAD$1;
185
+ }
186
+ /**
187
+ * Forward conversion for raw-price ceil surfaces.
188
+ * This matches sell-side maker assets, where the maker receives `sellerAssets` rounded up onchain.
189
+ * @param units - The units to convert.
190
+ * @param price - The raw tick price.
191
+ * @returns The ceil-rounded maker-side assets.
192
+ */
193
+ function unitsToCeilAssets(units, price) {
194
+ return (units * price + WAD$1 - 1n) / WAD$1;
195
+ }
196
+ /**
197
+ * Max-safe inverse for floor surfaces.
198
+ * It returns the greatest units value whose floor-rounded maker assets stay within `assets`.
199
+ * @param assets - The maker-side asset cap.
200
+ * @param price - The raw tick price.
201
+ * @returns The greatest safe obligation-units amount under `floor(units * price / WAD) <= assets`.
202
+ */
203
+ function floorAssetsToUnits(assets, price) {
204
+ return ((assets + 1n) * WAD$1 - 1n) / price;
205
+ }
206
+ /**
207
+ * Max-safe inverse for ceil surfaces.
208
+ * It returns the greatest units value whose ceil-rounded maker assets stay within `assets`.
209
+ * @param assets - The maker-side asset cap.
210
+ * @param price - The raw tick price.
211
+ * @returns The greatest safe obligation-units amount under `ceil(units * price / WAD) <= assets`.
212
+ */
213
+ function ceilAssetsToUnits(assets, price) {
214
+ return assets * WAD$1 / price;
215
+ }
139
216
  var InvalidTickError = class extends BaseError {
140
217
  name = "Tick.InvalidTickError";
141
218
  constructor(tick) {
@@ -157,7 +234,7 @@ function from$15(level) {
157
234
  return {
158
235
  tick: level.tick,
159
236
  price: price.toString(),
160
- assets: level.assets.toString(),
237
+ max_units: level.maxUnits.toString(),
161
238
  count: level.count
162
239
  };
163
240
  }
@@ -215,9 +292,11 @@ function from$14(obligation, quote, chainId) {
215
292
  collaterals: obligation.collaterals.map((c) => ({
216
293
  token: c.asset,
217
294
  lltv: c.lltv.toString(),
295
+ max_lif: c.maxLif.toString(),
218
296
  oracle: c.oracle
219
297
  })),
220
298
  maturity: obligation.maturity,
299
+ rcf_threshold: obligation.rcfThreshold.toString(),
221
300
  ask: {
222
301
  tick: quote.ask.tick,
223
302
  price: quote.ask.price.toString()
@@ -258,15 +337,15 @@ function from$13(input) {
258
337
  collaterals: input.collaterals.map((c) => ({
259
338
  token: c.asset,
260
339
  lltv: c.lltv.toString(),
340
+ max_lif: c.maxLif.toString(),
261
341
  oracle: c.oracle
262
342
  })),
263
- maturity: input.maturity
343
+ maturity: input.maturity,
344
+ rcf_threshold: input.rcfThreshold.toString()
264
345
  },
265
346
  buy: input.buy,
266
347
  maker: input.maker,
267
- assets: input.assets.toString(),
268
- obligation_units: input.obligationUnits.toString(),
269
- obligation_shares: input.obligationShares.toString(),
348
+ max_units: input.maxUnits.toString(),
270
349
  start: input.start,
271
350
  expiry: input.expiry,
272
351
  tick: input.tick,
@@ -274,7 +353,8 @@ function from$13(input) {
274
353
  session: input.session,
275
354
  callback: input.callback.address,
276
355
  callback_data: input.callback.data,
277
- receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
356
+ receiver_if_maker_is_seller: input.receiverIfMakerIsSeller,
357
+ exit_only: input.exitOnly
278
358
  },
279
359
  offer_hash: input.hash,
280
360
  obligation_id: input.obligationId,
@@ -327,15 +407,15 @@ const offerExample = {
327
407
  collaterals: [{
328
408
  token: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
329
409
  lltv: "860000000000000000",
410
+ max_lif: "0",
330
411
  oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
331
412
  }],
332
- maturity: 1761922799
413
+ maturity: 1761922799,
414
+ rcf_threshold: "0"
333
415
  },
334
416
  buy: false,
335
417
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
336
- assets: "369216000000000000000000",
337
- obligation_units: "0",
338
- obligation_shares: "0",
418
+ max_units: "369216000000000000000000",
339
419
  start: 1761922790,
340
420
  expiry: 1761922799,
341
421
  tick: 495,
@@ -343,7 +423,8 @@ const offerExample = {
343
423
  session: "0x0000000000000000000000000000000000000000000000000000000000000000",
344
424
  callback: "0x0000000000000000000000000000000000000000",
345
425
  callback_data: "0x",
346
- receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
426
+ receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
427
+ exit_only: false
347
428
  },
348
429
  offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
349
430
  obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf79",
@@ -377,11 +458,10 @@ const missingCollectorExample = {
377
458
  };
378
459
  const validateOfferExample = {
379
460
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
380
- assets: "369216000000000000000000",
381
- obligation_units: "0",
382
- obligation_shares: "0",
461
+ max_units: "369216000000000000000000",
383
462
  tick: 495,
384
463
  maturity: 1761922799,
464
+ rcf_threshold: "0",
385
465
  expiry: 1761922799,
386
466
  start: 1761922790,
387
467
  group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
@@ -392,13 +472,15 @@ const validateOfferExample = {
392
472
  collaterals: [{
393
473
  asset: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
394
474
  oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401",
395
- lltv: "860000000000000000"
475
+ lltv: "860000000000000000",
476
+ max_lif: "0"
396
477
  }],
397
478
  callback: {
398
479
  address: "0x0000000000000000000000000000000000000000",
399
480
  data: "0x"
400
481
  },
401
- receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
482
+ receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
483
+ exit_only: false
402
484
  };
403
485
  const routerStatusExample = {
404
486
  status: "live",
@@ -442,6 +524,10 @@ __decorate([ApiProperty({
442
524
  type: "string",
443
525
  example: "860000000000000000"
444
526
  })], CollateralResponse.prototype, "lltv", void 0);
527
+ __decorate([ApiProperty({
528
+ type: "string",
529
+ example: "0"
530
+ })], CollateralResponse.prototype, "max_lif", void 0);
445
531
  __decorate([ApiProperty({
446
532
  type: "string",
447
533
  example: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
@@ -459,6 +545,10 @@ __decorate([ApiProperty({
459
545
  type: "string",
460
546
  example: validateOfferExample.collaterals[0].lltv
461
547
  })], ValidateCollateralRequest.prototype, "lltv", void 0);
548
+ __decorate([ApiProperty({
549
+ type: "string",
550
+ example: validateOfferExample.collaterals[0].max_lif
551
+ })], ValidateCollateralRequest.prototype, "max_lif", void 0);
462
552
  var ValidateCallbackRequest = class {};
463
553
  __decorate([ApiProperty({
464
554
  type: "string",
@@ -503,6 +593,10 @@ __decorate([ApiProperty({
503
593
  type: "number",
504
594
  example: offerExample.offer.obligation.maturity
505
595
  })], ObligationOfferResponse.prototype, "maturity", void 0);
596
+ __decorate([ApiProperty({
597
+ type: "string",
598
+ example: offerExample.offer.obligation.rcf_threshold
599
+ })], ObligationOfferResponse.prototype, "rcf_threshold", void 0);
506
600
  var OfferDataResponse = class {};
507
601
  __decorate([ApiProperty({
508
602
  type: () => ObligationOfferResponse,
@@ -518,16 +612,8 @@ __decorate([ApiProperty({
518
612
  })], OfferDataResponse.prototype, "maker", void 0);
519
613
  __decorate([ApiProperty({
520
614
  type: "string",
521
- example: offerExample.offer.assets
522
- })], OfferDataResponse.prototype, "assets", void 0);
523
- __decorate([ApiProperty({
524
- type: "string",
525
- example: offerExample.offer.obligation_units
526
- })], OfferDataResponse.prototype, "obligation_units", void 0);
527
- __decorate([ApiProperty({
528
- type: "string",
529
- example: offerExample.offer.obligation_shares
530
- })], OfferDataResponse.prototype, "obligation_shares", void 0);
615
+ example: offerExample.offer.max_units
616
+ })], OfferDataResponse.prototype, "max_units", void 0);
531
617
  __decorate([ApiProperty({
532
618
  type: "number",
533
619
  example: offerExample.offer.start
@@ -562,6 +648,10 @@ __decorate([ApiProperty({
562
648
  type: "string",
563
649
  example: offerExample.offer.receiver_if_maker_is_seller
564
650
  })], OfferDataResponse.prototype, "receiver_if_maker_is_seller", void 0);
651
+ __decorate([ApiProperty({
652
+ type: "boolean",
653
+ example: offerExample.offer.exit_only
654
+ })], OfferDataResponse.prototype, "exit_only", void 0);
565
655
  var OfferListItemResponse = class {};
566
656
  __decorate([ApiProperty({
567
657
  type: () => OfferDataResponse,
@@ -624,6 +714,10 @@ __decorate([ApiProperty({
624
714
  type: "number",
625
715
  example: 1761922800
626
716
  })], ObligationResponse.prototype, "maturity", void 0);
717
+ __decorate([ApiProperty({
718
+ type: "string",
719
+ example: "0"
720
+ })], ObligationResponse.prototype, "rcf_threshold", void 0);
627
721
  __decorate([ApiProperty({ type: () => AskResponse })], ObligationResponse.prototype, "ask", void 0);
628
722
  __decorate([ApiProperty({ type: () => BidResponse })], ObligationResponse.prototype, "bid", void 0);
629
723
  var ObligationListResponse = class extends SuccessResponse {};
@@ -773,18 +867,9 @@ __decorate([ApiProperty({
773
867
  })], ValidateOfferRequest.prototype, "maker", void 0);
774
868
  __decorate([ApiProperty({
775
869
  type: "string",
776
- example: validateOfferExample.assets
777
- })], ValidateOfferRequest.prototype, "assets", void 0);
778
- __decorate([ApiProperty({
779
- type: "string",
780
- example: validateOfferExample.obligation_units,
781
- required: false
782
- })], ValidateOfferRequest.prototype, "obligation_units", void 0);
783
- __decorate([ApiProperty({
784
- type: "string",
785
- example: validateOfferExample.obligation_shares,
870
+ example: validateOfferExample.max_units,
786
871
  required: false
787
- })], ValidateOfferRequest.prototype, "obligation_shares", void 0);
872
+ })], ValidateOfferRequest.prototype, "max_units", void 0);
788
873
  __decorate([ApiProperty({
789
874
  type: "number",
790
875
  example: validateOfferExample.tick,
@@ -795,6 +880,10 @@ __decorate([ApiProperty({
795
880
  type: "number",
796
881
  example: validateOfferExample.maturity
797
882
  })], ValidateOfferRequest.prototype, "maturity", void 0);
883
+ __decorate([ApiProperty({
884
+ type: "string",
885
+ example: validateOfferExample.rcf_threshold
886
+ })], ValidateOfferRequest.prototype, "rcf_threshold", void 0);
798
887
  __decorate([ApiProperty({
799
888
  type: "number",
800
889
  example: validateOfferExample.expiry
@@ -831,6 +920,11 @@ __decorate([ApiProperty({
831
920
  type: "string",
832
921
  example: validateOfferExample.receiver_if_maker_is_seller
833
922
  })], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
923
+ __decorate([ApiProperty({
924
+ type: "boolean",
925
+ example: false,
926
+ required: false
927
+ })], ValidateOfferRequest.prototype, "exit_only", void 0);
834
928
  var ValidateOffersRequest = class {};
835
929
  __decorate([ApiProperty({
836
930
  type: "number",
@@ -909,7 +1003,7 @@ __decorate([ApiProperty({
909
1003
  __decorate([ApiProperty({
910
1004
  type: "string",
911
1005
  example: "369216000000000000000000"
912
- })], BookLevelResponse.prototype, "assets", void 0);
1006
+ })], BookLevelResponse.prototype, "max_units", void 0);
913
1007
  __decorate([ApiProperty({
914
1008
  type: "number",
915
1009
  example: 5
@@ -918,7 +1012,7 @@ const positionExample = {
918
1012
  chain_id: 1,
919
1013
  contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
920
1014
  user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
921
- obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf79",
1015
+ obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
922
1016
  reserved: "200000000000000000000",
923
1017
  block_number: 21345678
924
1018
  };
@@ -1533,7 +1627,7 @@ const OpenApi = async () => {
1533
1627
  info: {
1534
1628
  title: "Router API",
1535
1629
  version: "1.0.0",
1536
- description: "API for the Morpho Router"
1630
+ description: process.env.COMMIT_SHA ? `API for the Morpho Router — version: ${process.env.COMMIT_SHA.slice(0, 7)}` : "API for the Morpho Router"
1537
1631
  },
1538
1632
  servers: [{
1539
1633
  url: "https://router.morpho.dev",
@@ -1604,7 +1698,7 @@ function isValidOfferHashCursor(val) {
1604
1698
  return /^0x[a-f0-9]{64}$/i.test(val);
1605
1699
  }
1606
1700
  function isValidObligationIdCursor(val) {
1607
- return /^0x[a-f0-9]{40}$/i.test(val);
1701
+ return /^0x[a-f0-9]{64}$/i.test(val);
1608
1702
  }
1609
1703
  function isValidOfferCursor(val) {
1610
1704
  const [hash, obligationId, ...rest] = val.split(":");
@@ -1686,9 +1780,9 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
1686
1780
  description: "Side of the offer. Required when using obligation_id.",
1687
1781
  example: "buy"
1688
1782
  }),
1689
- obligation_id: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Obligation id must be a valid 20-byte hex string" }).transform((val) => val.toLowerCase()).optional().meta({
1783
+ obligation_id: z$1.string().regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).optional().meta({
1690
1784
  description: "Offers obligation id. Required when not using maker.",
1691
- example: "0x1234567890123456789012345678901234567890"
1785
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1692
1786
  }),
1693
1787
  maker: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Maker must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).optional().meta({
1694
1788
  description: "Maker address to filter offers by. Alternative to obligation_id + side.",
@@ -1773,9 +1867,9 @@ const GetObligationsQueryParams = z$1.object({
1773
1867
  example: "-ask,bid,maturity"
1774
1868
  })
1775
1869
  });
1776
- const GetObligationParams = z$1.object({ obligation_id: z$1.string({ error: "Obligation id is required and must be a valid 20-byte hex string" }).regex(/^0x[a-fA-F0-9]{40}$/, { error: "Obligation id must be a valid 20-byte hex string" }).transform((val) => val.toLowerCase()).meta({
1870
+ const GetObligationParams = z$1.object({ obligation_id: z$1.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
1777
1871
  description: "Obligation id",
1778
- example: "0x1234567890123456789012345678901234567890"
1872
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1779
1873
  }) });
1780
1874
  /** Validate a book cursor format: {side, lastTick, offersCursor} */
1781
1875
  function isValidBookCursor(cursorString) {
@@ -1810,9 +1904,9 @@ const HealthQueryParams = z$1.object({ strict: z$1.enum([
1810
1904
  }) });
1811
1905
  const GetBookParams = z$1.object({
1812
1906
  ...BookPaginationQueryParams.shape,
1813
- obligation_id: z$1.string({ error: "Obligation id is required and must be a valid 20-byte hex string" }).regex(/^0x[a-fA-F0-9]{40}$/, { error: "Obligation id must be a valid 20-byte hex string" }).transform((val) => val.toLowerCase()).meta({
1907
+ obligation_id: z$1.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
1814
1908
  description: "Obligation id",
1815
- example: "0x1234567890123456789012345678901234567890"
1909
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1816
1910
  }),
1817
1911
  side: z$1.enum(["buy", "sell"]).meta({
1818
1912
  description: "Side of the book (buy or sell).",
@@ -1900,57 +1994,75 @@ const MetaMorphoFactory = parseAbi(["event CreateMetaMorpho(address indexed meta
1900
1994
  //#region src/core/Abi/MorphoV2.ts
1901
1995
  const MorphoV2 = parseAbi([
1902
1996
  "constructor()",
1903
- "function collateralOf(bytes20 id, address user, uint256 collateralIndex) view returns (uint128)",
1904
- "function consume(bytes32 group, uint256 amount)",
1997
+ "function activatedCollaterals(bytes32 id, address user) view returns (uint128)",
1998
+ "function collateralOf(bytes32 id, address user, uint256 index) view returns (uint128)",
1905
1999
  "function consumed(address user, bytes32 group) view returns (uint256)",
1906
- "function debtOf(bytes20 id, address user) view returns (uint256)",
1907
- "function defaultFees(address loanToken, uint256 index) view returns (uint16)",
2000
+ "function creditAfterSlashing(bytes32 id, address user) view returns (uint256)",
2001
+ "function creditOf(bytes32 id, address user) view returns (uint256)",
2002
+ "function debtOf(bytes32 id, address user) view returns (uint256)",
2003
+ "function defaultFees(address loanToken, uint256) view returns (uint16)",
1908
2004
  "function feeSetter() view returns (address)",
1909
- "function fees(bytes20 id) view returns (uint16[6])",
2005
+ "function fees(bytes32 id) view returns (uint16[7])",
1910
2006
  "function flashLoan(address token, uint256 assets, address callback, bytes data)",
1911
- "function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, bytes20 id, address borrower) view returns (bool)",
1912
- "function liquidate((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address borrower, bytes data) returns (uint256, uint256)",
2007
+ "function isAuthorized(address authorizer, address authorized) view returns (bool)",
2008
+ "function isHealthy((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, bytes32 id, address borrower) view returns (bool)",
2009
+ "function liquidate((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address borrower, bytes data) returns (uint256, uint256)",
2010
+ "function maxCollateralPerUser(address collateralToken) view returns (uint256)",
2011
+ "function maxLif(uint256 lltv, uint256 cursor) pure returns (uint256)",
2012
+ "function maxTakeableAssets(address loanToken) view returns (uint256)",
2013
+ "function maxTotalUnits(address loanToken) view returns (uint128)",
2014
+ "function maxTradingFee(uint256 index) pure returns (uint256)",
1913
2015
  "function multicall(bytes[] calls)",
1914
- "function obligationCreated(bytes20 id) view returns (bool)",
1915
- "function obligationState(bytes20 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created, uint16[6] fees)",
2016
+ "function obligationCreated(bytes32 id) view returns (bool)",
2017
+ "function obligationState(bytes32 id) view returns (uint128 totalUnits, uint256 withdrawable, uint128 lossIndex, bool created)",
1916
2018
  "function owner() view returns (address)",
1917
- "function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, uint256 obligationUnits, address onBehalf)",
2019
+ "function repay((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 units, address onBehalf)",
1918
2020
  "function session(address user) view returns (bytes32)",
2021
+ "function setConsumed(bytes32 group, uint256 amount, address onBehalf)",
1919
2022
  "function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
1920
2023
  "function setFeeSetter(address newFeeSetter)",
1921
- "function setObligationTradingFee(bytes20 id, uint256 index, uint256 newTradingFee)",
2024
+ "function setIsAuthorized(address onBehalf, address authorized, bool newIsAuthorized)",
2025
+ "function setMaxCollateralPerUser(address collateralToken, uint256 newMaxCollateralPerUser)",
2026
+ "function setMaxTakeableAssets(address loanToken, uint256 newMaxTakeableAssets)",
2027
+ "function setMaxTotalUnits(address loanToken, uint128 newMaxTotalUnits)",
2028
+ "function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
1922
2029
  "function setOwner(address newOwner)",
1923
2030
  "function setTradingFeeRecipient(address feeRecipient)",
1924
- "function sharesOf(bytes20 id, address user) view returns (uint256)",
1925
- "function shuffleSession()",
1926
- "function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, uint256 collateralIndex, uint256 assets, address onBehalf)",
1927
- "function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256, uint256)",
1928
- "function toId((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation) view returns (bytes20)",
1929
- "function toObligation(bytes20 id) view returns ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue))",
1930
- "function totalShares(bytes20 id) view returns (uint256)",
1931
- "function totalUnits(bytes20 id) view returns (uint256)",
1932
- "function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation) returns (bytes20)",
1933
- "function tradingFee(bytes20 id, uint256 timeToMaturity) view returns (uint256)",
2031
+ "function shuffleSession(address onBehalf)",
2032
+ "function slash(bytes32 id, address user)",
2033
+ "function supplyCollateral((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 assets, address onBehalf)",
2034
+ "function take(uint256 units, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, bool buy, address maker, uint256 maxUnits, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller, bool exitOnly) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256)",
2035
+ "function toId((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation) view returns (bytes32)",
2036
+ "function toObligation(bytes32 id) view returns ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold))",
2037
+ "function totalUnits(bytes32 id) view returns (uint256)",
2038
+ "function touchObligation((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation) returns (bytes32)",
2039
+ "function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
1934
2040
  "function tradingFeeRecipient() view returns (address)",
1935
- "function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, uint256 obligationUnits, uint256 shares, address onBehalf, address receiver) returns (uint256, uint256)",
1936
- "function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation, uint256 collateralIndex, uint256 assets, address onBehalf, address receiver)",
1937
- "function withdrawable(bytes20 id) view returns (uint256)",
2041
+ "function userLossIndex(bytes32 id, address user) view returns (uint128)",
2042
+ "function withdraw((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 units, address onBehalf, address receiver)",
2043
+ "function withdrawCollateral((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 assets, address onBehalf, address receiver)",
2044
+ "function withdrawable(bytes32 id) view returns (uint256)",
1938
2045
  "event Constructor(address indexed owner)",
1939
- "event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
1940
2046
  "event FlashLoan(address indexed caller, address indexed token, uint256 assets)",
1941
- "event Liquidate(address indexed caller, bytes20 indexed id_, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address indexed borrower, uint256 badDebt)",
1942
- "event ObligationCreated(bytes20 indexed id_, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity, uint256 minCollatValue) obligation)",
1943
- "event Repay(address indexed caller, bytes20 indexed id_, uint256 obligationUnits, address indexed onBehalf)",
2047
+ "event Liquidate(address indexed caller, bytes32 indexed id_, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address indexed borrower, uint256 badDebt, uint256 latestLossIndex)",
2048
+ "event ObligationCreated(bytes32 indexed id_, (address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation)",
2049
+ "event Repay(address indexed caller, bytes32 indexed id_, uint256 units, address indexed onBehalf)",
2050
+ "event SetConsumed(address indexed caller, address indexed onBehalf, bytes32 indexed group, uint256 amount)",
1944
2051
  "event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
1945
2052
  "event SetFeeSetter(address indexed feeSetter)",
1946
- "event SetObligationTradingFee(bytes20 indexed id_, uint256 indexed index, uint256 newTradingFee)",
2053
+ "event SetIsAuthorized(address indexed caller, address indexed onBehalf, address indexed authorized, bool newIsAuthorized)",
2054
+ "event SetMaxCollateralPerUser(address indexed collateralToken, uint256 maxCollateralPerUser)",
2055
+ "event SetMaxTakeableAssets(address indexed loanToken, uint256 maxTakeableAssets)",
2056
+ "event SetMaxTotalUnits(address indexed loanToken, uint128 maxTotalUnits)",
2057
+ "event SetObligationTradingFee(bytes32 indexed id_, uint256 indexed index, uint256 newTradingFee)",
1947
2058
  "event SetOwner(address indexed owner)",
1948
2059
  "event SetTradingFeeRecipient(address indexed feeRecipient)",
1949
- "event ShuffleSession(address indexed user, bytes32 session)",
1950
- "event SupplyCollateral(address caller, bytes20 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf)",
1951
- "event Take(address caller, bytes20 indexed id_, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, address sellerReceiver, bytes32 group, uint256 consumed)",
1952
- "event Withdraw(address caller, bytes20 indexed id_, uint256 obligationUnits, uint256 shares, address indexed onBehalf, address indexed receiver)",
1953
- "event WithdrawCollateral(address caller, bytes20 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
2060
+ "event ShuffleSession(address indexed caller, address indexed onBehalf, bytes32 session)",
2061
+ "event Slash(address caller, bytes32 indexed id_, address indexed user, uint256 credit, uint256 latestLossIndex)",
2062
+ "event SupplyCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf)",
2063
+ "event Take(address caller, bytes32 indexed id_, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 units, address sellerReceiver, bytes32 group, uint256 consumed, uint256 totalUnits)",
2064
+ "event Withdraw(address caller, bytes32 indexed id_, uint256 units, address indexed onBehalf, address indexed receiver)",
2065
+ "event WithdrawCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
1954
2066
  ]);
1955
2067
 
1956
2068
  //#endregion
@@ -2243,8 +2355,8 @@ const chains$1 = {
2243
2355
  name: "base",
2244
2356
  custom: {
2245
2357
  morpho: {
2246
- address: "0x4C752Cdc4b13c9A6a933CbecfE050eC0BA0B45f9",
2247
- blockCreated: 42365274
2358
+ address: "0x26378861d9c740fe86e7472752aef5b1a783c60b",
2359
+ blockCreated: 43606117
2248
2360
  },
2249
2361
  morphoBlue: {
2250
2362
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -2273,8 +2385,8 @@ const chains$1 = {
2273
2385
  name: "ethereum-virtual-testnet",
2274
2386
  custom: {
2275
2387
  morpho: {
2276
- address: "0x9ac49a344376964291f7289663beb78e2952de44",
2277
- blockCreated: 23229385
2388
+ address: "0x94c576ee728ee290116ee65c0d1e9fed4a1b5041",
2389
+ blockCreated: 23244323
2278
2390
  },
2279
2391
  morphoBlue: {
2280
2392
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -2301,9 +2413,13 @@ const chains$1 = {
2301
2413
  ...anvil,
2302
2414
  id: ChainId.ANVIL,
2303
2415
  name: "anvil",
2416
+ contracts: { multicall3: {
2417
+ address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
2418
+ blockCreated: 0
2419
+ } },
2304
2420
  custom: {
2305
2421
  morpho: {
2306
- address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
2422
+ address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
2307
2423
  blockCreated: 0
2308
2424
  },
2309
2425
  morphoBlue: {
@@ -2311,8 +2427,8 @@ const chains$1 = {
2311
2427
  blockCreated: 0
2312
2428
  },
2313
2429
  mempool: {
2314
- address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
2315
- blockCreated: 23223727
2430
+ address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
2431
+ blockCreated: 0
2316
2432
  },
2317
2433
  vaults: { factories: {
2318
2434
  v1_0: {
@@ -2514,6 +2630,7 @@ var Random_exports = /* @__PURE__ */ __exportAll({
2514
2630
  address: () => address,
2515
2631
  bool: () => bool,
2516
2632
  bytes: () => bytes,
2633
+ createRng: () => createRng,
2517
2634
  float: () => float,
2518
2635
  hex: () => hex,
2519
2636
  int: () => int,
@@ -2531,7 +2648,19 @@ const hashSeed = (seed) => {
2531
2648
  }
2532
2649
  return hash >>> 0;
2533
2650
  };
2534
- const createSeededRng = (seed) => {
2651
+ /**
2652
+ * Creates an isolated seeded RNG instance — safe for concurrent use.
2653
+ * @param seed - Seed string used to derive the initial RNG state.
2654
+ */
2655
+ function createRng(seed) {
2656
+ const rng = createSeededRngFn(seed);
2657
+ return {
2658
+ float: () => rng(),
2659
+ int: (maxExclusive, min = 0) => Math.floor(rng() * (maxExclusive - min)) + min,
2660
+ bool: (probability = .5) => rng() < probability
2661
+ };
2662
+ }
2663
+ const createSeededRngFn = (seed) => {
2535
2664
  let state = hashSeed(seed);
2536
2665
  return () => {
2537
2666
  state += 1831565813;
@@ -2545,7 +2674,7 @@ const createSeededRng = (seed) => {
2545
2674
  */
2546
2675
  function withSeed(seed, fn) {
2547
2676
  const previous = currentRng;
2548
- currentRng = createSeededRng(seed);
2677
+ currentRng = createSeededRngFn(seed);
2549
2678
  try {
2550
2679
  return fn();
2551
2680
  } finally {
@@ -2556,7 +2685,7 @@ function withSeed(seed, fn) {
2556
2685
  * Seeds the global RNG for deterministic test runs.
2557
2686
  */
2558
2687
  function seed(seed) {
2559
- currentRng = createSeededRng(seed);
2688
+ currentRng = createSeededRngFn(seed);
2560
2689
  }
2561
2690
  /**
2562
2691
  * Returns a deterministic random float in [0, 1).
@@ -2678,6 +2807,7 @@ const transformAddress = (val, ctx) => {
2678
2807
  });
2679
2808
  return z$1.NEVER;
2680
2809
  };
2810
+ const AddressSchema = z$1.string().transform(transformAddress);
2681
2811
 
2682
2812
  //#endregion
2683
2813
  //#region src/core/LLTV.ts
@@ -2752,15 +2882,20 @@ const abi$1 = [
2752
2882
  type: "uint256",
2753
2883
  name: "lltv"
2754
2884
  },
2885
+ {
2886
+ type: "uint256",
2887
+ name: "maxLif"
2888
+ },
2755
2889
  {
2756
2890
  type: "address",
2757
2891
  name: "oracle"
2758
2892
  }
2759
2893
  ];
2760
2894
  const CollateralSchema = z$1.object({
2761
- asset: z$1.string().transform(transformAddress),
2762
- oracle: z$1.string().transform(transformAddress),
2763
- lltv: LLTVSchema
2895
+ asset: AddressSchema,
2896
+ oracle: AddressSchema,
2897
+ lltv: LLTVSchema,
2898
+ maxLif: z$1.bigint({ coerce: true }).min(0n)
2764
2899
  });
2765
2900
  const CollateralsSchema = z$1.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine((collaterals) => {
2766
2901
  for (let i = 1; i < collaterals.length; i++) if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) return false;
@@ -2778,6 +2913,7 @@ const from$10 = (parameters) => {
2778
2913
  return {
2779
2914
  asset: parameters.asset.toLowerCase(),
2780
2915
  lltv: from$11(parameters.lltv),
2916
+ maxLif: parameters.maxLif,
2781
2917
  oracle: parameters.oracle.toLowerCase()
2782
2918
  };
2783
2919
  };
@@ -2794,7 +2930,8 @@ function random$3() {
2794
2930
  return from$10({
2795
2931
  asset: address(),
2796
2932
  oracle: address(),
2797
- lltv: .965
2933
+ lltv: .965,
2934
+ maxLif: 0n
2798
2935
  });
2799
2936
  }
2800
2937
 
@@ -2916,14 +3053,8 @@ var Maturity_exports = /* @__PURE__ */ __exportAll({
2916
3053
  MaturityType: () => MaturityType,
2917
3054
  from: () => from$9
2918
3055
  });
2919
- const MaturitySchema = z$1.number().int().refine((maturity) => {
2920
- try {
2921
- from$9(maturity);
2922
- return true;
2923
- } catch (_e) {
2924
- return false;
2925
- }
2926
- }, { error: (issue) => {
3056
+ const MAX_TIMESTAMP_SECONDS = 999999999999;
3057
+ const MaturitySchema = z$1.number().int().max(MAX_TIMESTAMP_SECONDS).refine(isAt15UTC, { error: (issue) => {
2927
3058
  try {
2928
3059
  return `The maturity is set to ${/* @__PURE__ */ new Date(issue.input * 1e3)}. It must be at 15:00:00 UTC.`;
2929
3060
  } catch (_) {
@@ -2958,7 +3089,7 @@ function from$9(ts) {
2958
3089
  if (ts in MaturityOptions) return MaturityOptions[ts]();
2959
3090
  throw new InvalidOptionError(ts);
2960
3091
  }
2961
- if (typeof ts === "number" && ts > 0xe8d4a51000) throw new InvalidFormatError();
3092
+ if (typeof ts === "number" && ts > MAX_TIMESTAMP_SECONDS) throw new InvalidFormatError();
2962
3093
  if (!isAt15UTC(ts)) throw new InvalidDateError(ts);
2963
3094
  return ts;
2964
3095
  }
@@ -3052,10 +3183,10 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
3052
3183
  tupleAbi: () => tupleAbi
3053
3184
  });
3054
3185
  const ObligationSchema = z$1.object({
3055
- loanToken: z$1.string().transform(transformAddress),
3186
+ loanToken: AddressSchema,
3056
3187
  collaterals: CollateralsSchema,
3057
3188
  maturity: MaturitySchema,
3058
- minCollatValue: z$1.bigint({ coerce: true }).min(0n).optional().default(0n)
3189
+ rcfThreshold: z$1.bigint({ coerce: true }).min(0n)
3059
3190
  });
3060
3191
  const abi = [
3061
3192
  {
@@ -3073,7 +3204,7 @@ const abi = [
3073
3204
  },
3074
3205
  {
3075
3206
  type: "uint256",
3076
- name: "minCollatValue"
3207
+ name: "rcfThreshold"
3077
3208
  }
3078
3209
  ];
3079
3210
  const tupleAbi = [{
@@ -3095,10 +3226,12 @@ const tupleAbi = [{
3095
3226
  * Collateral.from({
3096
3227
  * asset: privateKeyToAccount(generatePrivateKey()).address,
3097
3228
  * oracle: privateKeyToAccount(generatePrivateKey()).address,
3098
- * lltv: 0.965
3229
+ * lltv: 0.965,
3230
+ * maxLif: 0n,
3099
3231
  * }),
3100
3232
  * ],
3101
3233
  * maturity: Maturity.from("end_of_next_quarter"),
3234
+ * rcfThreshold: 0n,
3102
3235
  * });
3103
3236
  * ```
3104
3237
  */
@@ -3112,7 +3245,7 @@ function from$8(parameters) {
3112
3245
  loanToken: parsedObligation.loanToken.toLowerCase(),
3113
3246
  collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
3114
3247
  maturity: parsedObligation.maturity,
3115
- minCollatValue: parsedObligation.minCollatValue
3248
+ rcfThreshold: parsedObligation.rcfThreshold
3116
3249
  };
3117
3250
  } catch (error) {
3118
3251
  throw new InvalidObligationError(error);
@@ -3129,8 +3262,7 @@ function fromSnakeCase$2(input) {
3129
3262
  }
3130
3263
  /**
3131
3264
  * Calculates a canonical key for an obligation payload.
3132
- * The key is computed as keccak256(abi.encode(loanToken, collaterals, maturity, minCollatValue)).
3133
- * If omitted, `minCollatValue` defaults to `0`.
3265
+ * The key is computed as keccak256(abi.encode(loanToken, collaterals, maturity, rcfThreshold)).
3134
3266
  * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}
3135
3267
  * @param parameters - {@link key.Parameters}
3136
3268
  * @returns The obligation key as a 32-byte hex string. {@link key.ReturnType}
@@ -3154,10 +3286,11 @@ function key(parameters) {
3154
3286
  parameters.collaterals.map((c) => ({
3155
3287
  token: c.asset.toLowerCase(),
3156
3288
  lltv: c.lltv,
3289
+ maxLif: c.maxLif,
3157
3290
  oracle: c.oracle.toLowerCase()
3158
3291
  })),
3159
3292
  BigInt(parameters.maturity),
3160
- parameters.minCollatValue ?? 0n
3293
+ parameters.rcfThreshold
3161
3294
  ]));
3162
3295
  }
3163
3296
  /**
@@ -3173,7 +3306,8 @@ function random$2() {
3173
3306
  return from$8({
3174
3307
  loanToken: address(),
3175
3308
  collaterals: [random$3()],
3176
- maturity: from$9("end_of_next_quarter")
3309
+ maturity: from$9("end_of_next_quarter"),
3310
+ rcfThreshold: 0n
3177
3311
  });
3178
3312
  }
3179
3313
  /**
@@ -3187,7 +3321,8 @@ function fromOffer$1(offer) {
3187
3321
  return from$8({
3188
3322
  loanToken: offer.loanToken,
3189
3323
  collaterals: offer.collaterals,
3190
- maturity: offer.maturity
3324
+ maturity: offer.maturity,
3325
+ rcfThreshold: offer.rcfThreshold
3191
3326
  });
3192
3327
  }
3193
3328
  var InvalidObligationError = class extends BaseError {
@@ -3224,27 +3359,27 @@ function creationCode(parameters) {
3224
3359
  collaterals: parameters.obligation.collaterals.map((collateral) => ({
3225
3360
  token: collateral.asset.toLowerCase(),
3226
3361
  lltv: collateral.lltv,
3362
+ maxLif: collateral.maxLif,
3227
3363
  oracle: collateral.oracle.toLowerCase()
3228
3364
  })),
3229
3365
  maturity: BigInt(parameters.obligation.maturity),
3230
- minCollatValue: 0n
3366
+ rcfThreshold: parameters.obligation.rcfThreshold
3231
3367
  }])]);
3232
3368
  }
3233
3369
  /**
3234
3370
  * Computes the same id as `IdLib.toId` in Solidity using the CREATE2 preimage:
3235
- * `keccak256(0xff ++ morphoV2 ++ chainId ++ keccak256(creationCode))`,
3236
- * then truncates to the lower 20 bytes.
3371
+ * `keccak256(0xff ++ morphoV2 ++ chainId ++ keccak256(creationCode))`.
3237
3372
  *
3238
3373
  * @param parameters - {@link toId.Parameters}
3239
- * @returns The obligation id. {@link toId.ReturnType}
3374
+ * @returns The 32-byte obligation id. {@link toId.ReturnType}
3240
3375
  */
3241
3376
  function toId(parameters) {
3242
- return `0x${keccak256(concatHex([
3377
+ return keccak256(concatHex([
3243
3378
  "0xff",
3244
3379
  parameters.morphoV2.toLowerCase(),
3245
3380
  numberToHex(BigInt(parameters.chainId), { size: 32 }),
3246
3381
  keccak256(creationCode(parameters))
3247
- ])).slice(-40)}`;
3382
+ ]));
3248
3383
  }
3249
3384
 
3250
3385
  //#endregion
@@ -3334,7 +3469,6 @@ var Offer_exports = /* @__PURE__ */ __exportAll({
3334
3469
  fromSnakeCase: () => fromSnakeCase$1,
3335
3470
  hash: () => hash,
3336
3471
  liquidateEvent: () => liquidateEvent,
3337
- obligationId: () => obligationId,
3338
3472
  random: () => random$1,
3339
3473
  repayEvent: () => repayEvent,
3340
3474
  serialize: () => serialize,
@@ -3352,12 +3486,11 @@ let Status = /* @__PURE__ */ function(Status) {
3352
3486
  }({});
3353
3487
  const OfferSchema = () => {
3354
3488
  return z$1.object({
3355
- maker: z$1.string().transform(transformAddress),
3356
- assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
3357
- obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
3358
- obligationShares: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
3489
+ maker: AddressSchema,
3490
+ maxUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
3359
3491
  tick: z$1.coerce.number().int().min(0).max(990),
3360
3492
  maturity: MaturitySchema,
3493
+ rcfThreshold: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
3361
3494
  expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
3362
3495
  start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
3363
3496
  group: z$1.union([
@@ -3371,13 +3504,14 @@ const OfferSchema = () => {
3371
3504
  z$1.bigint()
3372
3505
  ]).optional().default("0x0000000000000000000000000000000000000000000000000000000000000000").transform(transformBytes32),
3373
3506
  buy: z$1.boolean(),
3374
- loanToken: z$1.string().transform(transformAddress),
3507
+ loanToken: AddressSchema,
3375
3508
  collaterals: CollateralsSchema,
3376
3509
  callback: z$1.object({
3377
- address: z$1.string().transform(transformAddress),
3510
+ address: AddressSchema,
3378
3511
  data: z$1.string().transform(transformHex)
3379
3512
  }),
3380
- receiverIfMakerIsSeller: z$1.string().transform(transformAddress)
3513
+ receiverIfMakerIsSeller: AddressSchema,
3514
+ exitOnly: z$1.boolean().optional().default(false)
3381
3515
  }).refine((data) => data.start < data.expiry, {
3382
3516
  message: "start must be before expiry",
3383
3517
  path: ["start"]
@@ -3429,11 +3563,10 @@ function toSnakeCase(offer) {
3429
3563
  */
3430
3564
  const serialize = (offer) => ({
3431
3565
  maker: offer.maker,
3432
- assets: offer.assets.toString(),
3433
- obligationUnits: offer.obligationUnits.toString(),
3434
- obligationShares: offer.obligationShares.toString(),
3566
+ maxUnits: offer.maxUnits.toString(),
3435
3567
  tick: offer.tick,
3436
3568
  maturity: Number(offer.maturity),
3569
+ rcfThreshold: offer.rcfThreshold.toString(),
3437
3570
  expiry: Number(offer.expiry),
3438
3571
  start: Number(offer.start),
3439
3572
  group: offer.group,
@@ -3443,13 +3576,15 @@ const serialize = (offer) => ({
3443
3576
  collaterals: offer.collaterals.map((c) => ({
3444
3577
  asset: c.asset,
3445
3578
  oracle: c.oracle,
3446
- lltv: c.lltv.toString()
3579
+ lltv: c.lltv.toString(),
3580
+ maxLif: c.maxLif.toString()
3447
3581
  })),
3448
3582
  callback: {
3449
3583
  address: offer.callback.address,
3450
3584
  data: offer.callback.data
3451
3585
  },
3452
3586
  receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
3587
+ exitOnly: offer.exitOnly,
3453
3588
  hash: hash(offer)
3454
3589
  });
3455
3590
  /**
@@ -3486,7 +3621,7 @@ function random$1(config) {
3486
3621
  const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
3487
3622
  const unit = BigInt(10) ** BigInt(loanTokenDecimals);
3488
3623
  const amountBase = BigInt(100 + int(999901));
3489
- const assetsScaled = config?.assets ?? amountBase * unit;
3624
+ const maxUnitsScaled = config?.maxUnits ?? amountBase * unit;
3490
3625
  const emptyCallback = {
3491
3626
  address: zeroAddress,
3492
3627
  data: "0x"
@@ -3494,11 +3629,10 @@ function random$1(config) {
3494
3629
  const maker = config?.maker ?? address();
3495
3630
  return from$7({
3496
3631
  maker,
3497
- assets: assetsScaled,
3498
- obligationUnits: config?.obligationUnits ?? 0n,
3499
- obligationShares: config?.obligationShares ?? 0n,
3632
+ maxUnits: maxUnitsScaled,
3500
3633
  tick,
3501
3634
  maturity,
3635
+ rcfThreshold: config?.rcfThreshold ?? 0n,
3502
3636
  expiry: config?.expiry ?? maturity - 1,
3503
3637
  start: config?.start ?? maturity - 10,
3504
3638
  group: config?.group ?? hex(32),
@@ -3510,7 +3644,8 @@ function random$1(config) {
3510
3644
  lltv
3511
3645
  })).sort((a, b) => a.asset.localeCompare(b.asset)),
3512
3646
  callback: config?.callback ?? emptyCallback,
3513
- receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker
3647
+ receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker,
3648
+ exitOnly: config?.exitOnly ?? false
3514
3649
  });
3515
3650
  }
3516
3651
  const weightedChoice = (pairs) => {
@@ -3537,124 +3672,150 @@ function hash(offer) {
3537
3672
  return computed;
3538
3673
  }
3539
3674
  /**
3540
- * Calculates the onchain obligation id for an offer.
3541
- * The id is computed with {@link Id.toId}.
3542
- * @param offer - The offer to calculate the obligation id for.
3543
- * @param parameters - The chain context used by the onchain id function.
3544
- * @returns The obligation id as a 20-byte hex string.
3675
+ * ABI layout matching the Solidity `Offer` struct used by `abi.encode(offer)` in the contract.
3676
+ *
3677
+ * This is a **single top-level tuple** Solidity's `abi.encode(struct)` encodes the struct as one
3678
+ * tuple parameter, not as separate parameters per field. Field order and nesting must exactly
3679
+ * mirror `contracts/interfaces/IMidnight.sol`:
3680
+ *
3681
+ * ```
3682
+ * struct Offer {
3683
+ * Obligation obligation; // nested tuple
3684
+ * bool buy;
3685
+ * address maker;
3686
+ * uint256 maxUnits;
3687
+ * uint256 start;
3688
+ * uint256 expiry;
3689
+ * uint256 tick;
3690
+ * bytes32 group;
3691
+ * bytes32 session;
3692
+ * address callback;
3693
+ * bytes callbackData;
3694
+ * address receiverIfMakerIsSeller;
3695
+ * bool exitOnly;
3696
+ * }
3697
+ * ```
3545
3698
  */
3546
- function obligationId(offer, parameters) {
3547
- return toId({
3548
- chainId: parameters.chainId,
3549
- morphoV2: parameters.morphoV2,
3550
- obligation: from$8({
3551
- loanToken: offer.loanToken,
3552
- collaterals: offer.collaterals,
3553
- maturity: offer.maturity
3554
- })
3555
- });
3556
- }
3557
- const OfferAbi = [
3558
- {
3559
- name: "maker",
3560
- type: "address"
3561
- },
3562
- {
3563
- name: "assets",
3564
- type: "uint256"
3565
- },
3566
- {
3567
- name: "obligationUnits",
3568
- type: "uint256"
3569
- },
3570
- {
3571
- name: "obligationShares",
3572
- type: "uint256"
3573
- },
3574
- {
3575
- name: "tick",
3576
- type: "uint256"
3577
- },
3578
- {
3579
- name: "maturity",
3580
- type: "uint256"
3581
- },
3582
- {
3583
- name: "expiry",
3584
- type: "uint256"
3585
- },
3586
- {
3587
- name: "group",
3588
- type: "bytes32"
3589
- },
3590
- {
3591
- name: "session",
3592
- type: "bytes32"
3593
- },
3594
- {
3595
- name: "buy",
3596
- type: "bool"
3597
- },
3598
- {
3599
- name: "loanToken",
3600
- type: "address"
3601
- },
3602
- {
3603
- name: "start",
3604
- type: "uint256"
3605
- },
3606
- {
3607
- name: "collaterals",
3608
- type: "tuple[]",
3609
- components: [
3610
- {
3611
- name: "asset",
3612
- type: "address"
3613
- },
3614
- {
3615
- name: "oracle",
3616
- type: "address"
3617
- },
3618
- {
3619
- name: "lltv",
3620
- type: "uint256"
3621
- }
3622
- ]
3623
- },
3624
- {
3625
- name: "callback",
3626
- type: "tuple",
3627
- components: [{
3628
- name: "address",
3699
+ const OfferAbi = [{
3700
+ name: "offer",
3701
+ type: "tuple",
3702
+ components: [
3703
+ {
3704
+ name: "obligation",
3705
+ type: "tuple",
3706
+ components: [
3707
+ {
3708
+ name: "loanToken",
3709
+ type: "address"
3710
+ },
3711
+ {
3712
+ name: "collaterals",
3713
+ type: "tuple[]",
3714
+ components: [
3715
+ {
3716
+ name: "token",
3717
+ type: "address"
3718
+ },
3719
+ {
3720
+ name: "lltv",
3721
+ type: "uint256"
3722
+ },
3723
+ {
3724
+ name: "maxLif",
3725
+ type: "uint256"
3726
+ },
3727
+ {
3728
+ name: "oracle",
3729
+ type: "address"
3730
+ }
3731
+ ]
3732
+ },
3733
+ {
3734
+ name: "maturity",
3735
+ type: "uint256"
3736
+ },
3737
+ {
3738
+ name: "rcfThreshold",
3739
+ type: "uint256"
3740
+ }
3741
+ ]
3742
+ },
3743
+ {
3744
+ name: "buy",
3745
+ type: "bool"
3746
+ },
3747
+ {
3748
+ name: "maker",
3629
3749
  type: "address"
3630
- }, {
3631
- name: "data",
3750
+ },
3751
+ {
3752
+ name: "maxUnits",
3753
+ type: "uint256"
3754
+ },
3755
+ {
3756
+ name: "start",
3757
+ type: "uint256"
3758
+ },
3759
+ {
3760
+ name: "expiry",
3761
+ type: "uint256"
3762
+ },
3763
+ {
3764
+ name: "tick",
3765
+ type: "uint256"
3766
+ },
3767
+ {
3768
+ name: "group",
3769
+ type: "bytes32"
3770
+ },
3771
+ {
3772
+ name: "session",
3773
+ type: "bytes32"
3774
+ },
3775
+ {
3776
+ name: "callback",
3777
+ type: "address"
3778
+ },
3779
+ {
3780
+ name: "callbackData",
3632
3781
  type: "bytes"
3633
- }]
3634
- },
3635
- {
3636
- name: "receiverIfMakerIsSeller",
3637
- type: "address"
3638
- }
3639
- ];
3782
+ },
3783
+ {
3784
+ name: "receiverIfMakerIsSeller",
3785
+ type: "address"
3786
+ },
3787
+ {
3788
+ name: "exitOnly",
3789
+ type: "bool"
3790
+ }
3791
+ ]
3792
+ }];
3640
3793
  function encode$1(offer) {
3641
- return encodeAbiParameters(OfferAbi, [
3642
- offer.maker,
3643
- offer.assets,
3644
- offer.obligationUnits,
3645
- offer.obligationShares,
3646
- BigInt(offer.tick),
3647
- BigInt(offer.maturity),
3648
- BigInt(offer.expiry),
3649
- offer.group,
3650
- offer.session,
3651
- offer.buy,
3652
- offer.loanToken,
3653
- BigInt(offer.start),
3654
- offer.collaterals,
3655
- offer.callback,
3656
- offer.receiverIfMakerIsSeller
3657
- ]);
3794
+ return encodeAbiParameters(OfferAbi, [{
3795
+ obligation: {
3796
+ loanToken: offer.loanToken,
3797
+ collaterals: offer.collaterals.map((c) => ({
3798
+ token: c.asset,
3799
+ lltv: c.lltv,
3800
+ maxLif: c.maxLif,
3801
+ oracle: c.oracle
3802
+ })),
3803
+ maturity: BigInt(offer.maturity),
3804
+ rcfThreshold: offer.rcfThreshold
3805
+ },
3806
+ buy: offer.buy,
3807
+ maker: offer.maker,
3808
+ maxUnits: offer.maxUnits,
3809
+ start: BigInt(offer.start),
3810
+ expiry: BigInt(offer.expiry),
3811
+ tick: BigInt(offer.tick),
3812
+ group: offer.group,
3813
+ session: offer.session,
3814
+ callback: offer.callback.address,
3815
+ callbackData: offer.callback.data,
3816
+ receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
3817
+ exitOnly: offer.exitOnly
3818
+ }]);
3658
3819
  }
3659
3820
  function decode$1(data) {
3660
3821
  let decoded;
@@ -3663,31 +3824,33 @@ function decode$1(data) {
3663
3824
  } catch (error) {
3664
3825
  throw new InvalidOfferError(error);
3665
3826
  }
3827
+ const s = decoded[0];
3666
3828
  return from$7({
3667
- maker: decoded[0],
3668
- assets: decoded[1],
3669
- obligationUnits: decoded[2],
3670
- obligationShares: decoded[3],
3671
- tick: Number(decoded[4]),
3672
- maturity: from$9(Number(decoded[5])),
3673
- expiry: Number(decoded[6]),
3674
- group: decoded[7],
3675
- session: decoded[8],
3676
- buy: decoded[9],
3677
- loanToken: decoded[10],
3678
- start: Number(decoded[11]),
3679
- collaterals: decoded[12].map((c) => {
3829
+ loanToken: s.obligation.loanToken,
3830
+ collaterals: s.obligation.collaterals.map((c) => {
3680
3831
  return from$10({
3681
- asset: c.asset,
3832
+ asset: c.token,
3682
3833
  oracle: c.oracle,
3683
- lltv: c.lltv
3834
+ lltv: c.lltv,
3835
+ maxLif: c.maxLif
3684
3836
  });
3685
3837
  }),
3838
+ maturity: from$9(Number(s.obligation.maturity)),
3839
+ rcfThreshold: s.obligation.rcfThreshold,
3840
+ buy: s.buy,
3841
+ maker: s.maker,
3842
+ maxUnits: s.maxUnits,
3843
+ start: Number(s.start),
3844
+ expiry: Number(s.expiry),
3845
+ tick: Number(s.tick),
3846
+ group: s.group,
3847
+ session: s.session,
3686
3848
  callback: {
3687
- address: decoded[13].address,
3688
- data: decoded[13].data
3849
+ address: s.callback,
3850
+ data: s.callbackData
3689
3851
  },
3690
- receiverIfMakerIsSeller: decoded[14]
3852
+ receiverIfMakerIsSeller: s.receiverIfMakerIsSeller,
3853
+ exitOnly: s.exitOnly
3691
3854
  });
3692
3855
  }
3693
3856
  /**
@@ -3705,9 +3868,9 @@ const takeEvent = {
3705
3868
  },
3706
3869
  {
3707
3870
  name: "id_",
3708
- type: "bytes20",
3871
+ type: "bytes32",
3709
3872
  indexed: true,
3710
- internalType: "bytes20"
3873
+ internalType: "bytes32"
3711
3874
  },
3712
3875
  {
3713
3876
  name: "maker",
@@ -3740,29 +3903,11 @@ const takeEvent = {
3740
3903
  internalType: "uint256"
3741
3904
  },
3742
3905
  {
3743
- name: "obligationUnits",
3906
+ name: "units",
3744
3907
  type: "uint256",
3745
3908
  indexed: false,
3746
3909
  internalType: "uint256"
3747
3910
  },
3748
- {
3749
- name: "obligationShares",
3750
- type: "uint256",
3751
- indexed: false,
3752
- internalType: "uint256"
3753
- },
3754
- {
3755
- name: "buyerIsLender",
3756
- type: "bool",
3757
- indexed: false,
3758
- internalType: "bool"
3759
- },
3760
- {
3761
- name: "sellerIsBorrower",
3762
- type: "bool",
3763
- indexed: false,
3764
- internalType: "bool"
3765
- },
3766
3911
  {
3767
3912
  name: "sellerReceiver",
3768
3913
  type: "address",
@@ -3780,19 +3925,31 @@ const takeEvent = {
3780
3925
  type: "uint256",
3781
3926
  indexed: false,
3782
3927
  internalType: "uint256"
3928
+ },
3929
+ {
3930
+ name: "totalUnits",
3931
+ type: "uint256",
3932
+ indexed: false,
3933
+ internalType: "uint256"
3783
3934
  }
3784
3935
  ],
3785
3936
  anonymous: false
3786
3937
  };
3787
3938
  /**
3788
- * ABI for the Consume event emitted by the Obligation contract.
3939
+ * ABI for the SetConsumed event emitted by the Morpho V2 contract.
3789
3940
  */
3790
3941
  const consumedEvent = {
3791
3942
  type: "event",
3792
- name: "Consume",
3943
+ name: "SetConsumed",
3793
3944
  inputs: [
3794
3945
  {
3795
- name: "user",
3946
+ name: "caller",
3947
+ type: "address",
3948
+ indexed: true,
3949
+ internalType: "address"
3950
+ },
3951
+ {
3952
+ name: "onBehalf",
3796
3953
  type: "address",
3797
3954
  indexed: true,
3798
3955
  internalType: "address"
@@ -3827,12 +3984,12 @@ const repayEvent = {
3827
3984
  },
3828
3985
  {
3829
3986
  name: "id_",
3830
- type: "bytes20",
3987
+ type: "bytes32",
3831
3988
  indexed: true,
3832
- internalType: "bytes20"
3989
+ internalType: "bytes32"
3833
3990
  },
3834
3991
  {
3835
- name: "obligationUnits",
3992
+ name: "units",
3836
3993
  type: "uint256",
3837
3994
  indexed: false,
3838
3995
  internalType: "uint256"
@@ -3861,9 +4018,9 @@ const liquidateEvent = {
3861
4018
  },
3862
4019
  {
3863
4020
  name: "id_",
3864
- type: "bytes20",
4021
+ type: "bytes32",
3865
4022
  indexed: true,
3866
- internalType: "bytes20"
4023
+ internalType: "bytes32"
3867
4024
  },
3868
4025
  {
3869
4026
  name: "collateralIndex",
@@ -3894,6 +4051,12 @@ const liquidateEvent = {
3894
4051
  type: "uint256",
3895
4052
  indexed: false,
3896
4053
  internalType: "uint256"
4054
+ },
4055
+ {
4056
+ name: "latestLossIndex",
4057
+ type: "uint256",
4058
+ indexed: false,
4059
+ internalType: "uint256"
3897
4060
  }
3898
4061
  ],
3899
4062
  anonymous: false
@@ -3913,9 +4076,9 @@ const supplyCollateralEvent = {
3913
4076
  },
3914
4077
  {
3915
4078
  name: "id_",
3916
- type: "bytes20",
4079
+ type: "bytes32",
3917
4080
  indexed: true,
3918
- internalType: "bytes20"
4081
+ internalType: "bytes32"
3919
4082
  },
3920
4083
  {
3921
4084
  name: "collateral",
@@ -3953,9 +4116,9 @@ const withdrawCollateralEvent = {
3953
4116
  },
3954
4117
  {
3955
4118
  name: "id_",
3956
- type: "bytes20",
4119
+ type: "bytes32",
3957
4120
  indexed: true,
3958
- internalType: "bytes20"
4121
+ internalType: "bytes32"
3959
4122
  },
3960
4123
  {
3961
4124
  name: "collateral",
@@ -4228,7 +4391,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
4228
4391
  });
4229
4392
  /**
4230
4393
  * Time breakpoints in seconds for piecewise linear fee interpolation.
4231
- * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d.
4394
+ * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d, 360d.
4232
4395
  */
4233
4396
  const BREAKPOINTS = [
4234
4397
  0n,
@@ -4236,21 +4399,22 @@ const BREAKPOINTS = [
4236
4399
  604800n,
4237
4400
  2592000n,
4238
4401
  7776000n,
4239
- 15552000n
4402
+ 15552000n,
4403
+ 31104000n
4240
4404
  ];
4241
4405
  /** WAD constant (1e18) for fee scaling. */
4242
4406
  const WAD = 10n ** 18n;
4243
4407
  /**
4244
- * Create a TradingFee from an activation flag and 6 fee values.
4408
+ * Create a TradingFee from an activation flag and 7 fee values.
4245
4409
  * @param activated - Whether the fee is active.
4246
- * @param fees - Tuple of 6 fee values in WAD (one per breakpoint: 0d, 1d, 7d, 30d, 90d, 180d).
4410
+ * @param fees - Tuple of 7 fee values in WAD (one per breakpoint: 0d, 1d, 7d, 30d, 90d, 180d, 360d).
4247
4411
  * @returns A new TradingFee instance.
4248
4412
  * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
4249
- * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
4413
+ * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 7 elements.
4250
4414
  */
4251
4415
  function from$3(activated, fees) {
4252
- if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
4253
- for (let i = 0; i < 6; i++) {
4416
+ if (fees.length !== 7) throw new InvalidFeesLengthError(fees.length);
4417
+ for (let i = 0; i < 7; i++) {
4254
4418
  const fee = fees[i];
4255
4419
  if (fee < 0n || fee > WAD) throw new InvalidFeeError(fee, i);
4256
4420
  }
@@ -4269,7 +4433,9 @@ function from$3(activated, fees) {
4269
4433
  function compute(tradingFee, timeToMaturity) {
4270
4434
  if (!tradingFee._activated) return 0n;
4271
4435
  const time = BigInt(Math.max(0, Math.floor(timeToMaturity)));
4272
- if (time >= BREAKPOINTS[5]) return tradingFee._fees[5];
4436
+ const maxBreakpoint = BREAKPOINTS[BREAKPOINTS.length - 1];
4437
+ const maxFee = tradingFee._fees[tradingFee._fees.length - 1];
4438
+ if (time >= maxBreakpoint) return maxFee;
4273
4439
  const { index, start, end } = getSegment(time);
4274
4440
  const feeLower = tradingFee._fees[index];
4275
4441
  const feeUpper = tradingFee._fees[index + 1];
@@ -4309,7 +4475,7 @@ function deactivate(tradingFee) {
4309
4475
  /**
4310
4476
  * Get the fee values at each breakpoint.
4311
4477
  * @param tradingFee - The TradingFee instance.
4312
- * @returns The tuple of 6 fee values.
4478
+ * @returns The tuple of 7 fee values.
4313
4479
  */
4314
4480
  function getFees(tradingFee) {
4315
4481
  return tradingFee._fees;
@@ -4320,30 +4486,21 @@ function getFees(tradingFee) {
4320
4486
  * @returns Object with index, start, and end of the segment.
4321
4487
  */
4322
4488
  function getSegment(timeToMaturity) {
4323
- if (timeToMaturity < BREAKPOINTS[1]) return {
4324
- index: 0,
4325
- start: BREAKPOINTS[0],
4326
- end: BREAKPOINTS[1]
4327
- };
4328
- if (timeToMaturity < BREAKPOINTS[2]) return {
4329
- index: 1,
4330
- start: BREAKPOINTS[1],
4331
- end: BREAKPOINTS[2]
4332
- };
4333
- if (timeToMaturity < BREAKPOINTS[3]) return {
4334
- index: 2,
4335
- start: BREAKPOINTS[2],
4336
- end: BREAKPOINTS[3]
4337
- };
4338
- if (timeToMaturity < BREAKPOINTS[4]) return {
4339
- index: 3,
4340
- start: BREAKPOINTS[3],
4341
- end: BREAKPOINTS[4]
4342
- };
4489
+ for (let segmentEndIndex = 1; segmentEndIndex < BREAKPOINTS.length; segmentEndIndex++) {
4490
+ const end = BREAKPOINTS[segmentEndIndex];
4491
+ if (timeToMaturity < end) {
4492
+ const index = segmentEndIndex - 1;
4493
+ return {
4494
+ index,
4495
+ start: BREAKPOINTS[index],
4496
+ end
4497
+ };
4498
+ }
4499
+ }
4343
4500
  return {
4344
- index: 4,
4345
- start: BREAKPOINTS[4],
4346
- end: BREAKPOINTS[5]
4501
+ index: BREAKPOINTS.length - 2,
4502
+ start: BREAKPOINTS[BREAKPOINTS.length - 2],
4503
+ end: BREAKPOINTS[BREAKPOINTS.length - 1]
4347
4504
  };
4348
4505
  }
4349
4506
  /** Error thrown when a fee value is invalid (negative or exceeds WAD). */
@@ -4353,11 +4510,11 @@ var InvalidFeeError = class extends BaseError {
4353
4510
  super(`Invalid fee at index ${index}: ${fee}. Fee must be between 0 and ${WAD} (WAD).`);
4354
4511
  }
4355
4512
  };
4356
- /** Error thrown when fees array doesn't have exactly 6 elements. */
4513
+ /** Error thrown when fees array doesn't have exactly 7 elements. */
4357
4514
  var InvalidFeesLengthError = class extends BaseError {
4358
4515
  name = "TradingFee.InvalidFeesLengthError";
4359
4516
  constructor(length) {
4360
- super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
4517
+ super(`Invalid fees length: ${length}. Expected exactly 7 fee values.`);
4361
4518
  }
4362
4519
  };
4363
4520
 
@@ -4395,6 +4552,9 @@ function from$2(parameters) {
4395
4552
  var Tree_exports = /* @__PURE__ */ __exportAll({
4396
4553
  DecodeError: () => DecodeError,
4397
4554
  EncodeError: () => EncodeError,
4555
+ MAX_COMPRESSED_OFFERS_BYTES: () => MAX_COMPRESSED_OFFERS_BYTES,
4556
+ MAX_DECOMPRESSED_OFFERS_BYTES: () => MAX_DECOMPRESSED_OFFERS_BYTES,
4557
+ MAX_OFFERS_PER_TREE: () => MAX_OFFERS_PER_TREE,
4398
4558
  SignatureDomainError: () => SignatureDomainError,
4399
4559
  TreeError: () => TreeError,
4400
4560
  VERSION: () => VERSION$1,
@@ -4406,7 +4566,16 @@ var Tree_exports = /* @__PURE__ */ __exportAll({
4406
4566
  signatureDomain: () => signatureDomain,
4407
4567
  signatureTypes: () => signatureTypes
4408
4568
  });
4409
- const VERSION$1 = 1;
4569
+ const VERSION$1 = 2;
4570
+ const MAX_COMPRESSED_OFFERS_BYTES = 1e6;
4571
+ const MAX_DECOMPRESSED_OFFERS_BYTES = 4e6;
4572
+ const MAX_OFFERS_PER_TREE = 100;
4573
+ const ROOT_BYTES = 32;
4574
+ const SIGNATURE_BYTES = 65;
4575
+ const MIN_SIGNED_PAYLOAD_BYTES = 1 + ROOT_BYTES + SIGNATURE_BYTES;
4576
+ const INFLATE_INPUT_CHUNK_BYTES = 64 * 1024;
4577
+ const UTF8_ENCODER = new TextEncoder();
4578
+ const UTF8_DECODER = new TextDecoder();
4410
4579
  /**
4411
4580
  * EIP-712 types for signing the tree root (Root(bytes32 root)).
4412
4581
  */
@@ -4423,29 +4592,83 @@ const signatureTypes = {
4423
4592
  type: "bytes32"
4424
4593
  }]
4425
4594
  };
4426
- const normalizeHash = (hash) => hash.toLowerCase();
4595
+ const gzipOffersPayload = (payload, errorFactory) => {
4596
+ const payloadBytes = UTF8_ENCODER.encode(payload);
4597
+ if (payloadBytes.length > MAX_DECOMPRESSED_OFFERS_BYTES) throw errorFactory(`decompressed offers exceed ${MAX_DECOMPRESSED_OFFERS_BYTES} bytes`);
4598
+ try {
4599
+ const compressed = gzip(payloadBytes);
4600
+ if (compressed.length > MAX_COMPRESSED_OFFERS_BYTES) throw errorFactory(`compressed offers exceed ${MAX_COMPRESSED_OFFERS_BYTES} bytes`);
4601
+ return compressed;
4602
+ } catch (error) {
4603
+ if (error instanceof BaseError) throw error;
4604
+ throw errorFactory("compression failed");
4605
+ }
4606
+ };
4607
+ const gunzipOffersPayload = (compressed, errorFactory) => {
4608
+ if (compressed.length === 0) throw errorFactory("decompression failed");
4609
+ if (compressed.length > MAX_COMPRESSED_OFFERS_BYTES) throw errorFactory(`compressed offers exceed ${MAX_COMPRESSED_OFFERS_BYTES} bytes`);
4610
+ let totalLength = 0;
4611
+ const inflate = new Inflate();
4612
+ const defaultOnData = inflate.onData.bind(inflate);
4613
+ inflate.onData = (chunk) => {
4614
+ totalLength += chunk.length;
4615
+ if (totalLength > MAX_DECOMPRESSED_OFFERS_BYTES) throw errorFactory(`decompressed offers exceed ${MAX_DECOMPRESSED_OFFERS_BYTES} bytes`);
4616
+ defaultOnData(chunk);
4617
+ };
4618
+ try {
4619
+ for (let offset = 0; offset < compressed.length; offset += INFLATE_INPUT_CHUNK_BYTES) {
4620
+ const end = Math.min(offset + INFLATE_INPUT_CHUNK_BYTES, compressed.length);
4621
+ inflate.push(compressed.subarray(offset, end), end === compressed.length);
4622
+ }
4623
+ } catch (error) {
4624
+ if (error instanceof BaseError) throw error;
4625
+ throw errorFactory("decompression failed");
4626
+ }
4627
+ if (inflate.err !== 0) throw errorFactory(inflate.msg || "decompression failed");
4628
+ if (!(inflate.result instanceof Uint8Array)) throw errorFactory("decompression failed");
4629
+ return UTF8_DECODER.decode(inflate.result);
4630
+ };
4631
+ const parseRawOffersPayload = (decoded, errorFactory) => {
4632
+ let rawOffers;
4633
+ try {
4634
+ rawOffers = JSON.parse(decoded);
4635
+ } catch {
4636
+ throw errorFactory("JSON parse failed");
4637
+ }
4638
+ if (!Array.isArray(rawOffers)) throw errorFactory("offers payload must be a JSON array");
4639
+ if (rawOffers.length > MAX_OFFERS_PER_TREE) throw errorFactory(`offers payload exceeds ${MAX_OFFERS_PER_TREE} offers`);
4640
+ return rawOffers;
4641
+ };
4642
+ const assertUniqueOfferHashes = (offers, errorFactory) => {
4643
+ const seen = /* @__PURE__ */ new Set();
4644
+ for (const offer of offers) {
4645
+ const hash$1 = hash(offer);
4646
+ if (seen.has(hash$1)) throw errorFactory(`duplicate offer hash ${hash$1}`);
4647
+ seen.add(hash$1);
4648
+ }
4649
+ };
4427
4650
  /**
4428
4651
  * Builds a Merkle tree from a list of offers.
4429
4652
  *
4430
4653
  * Leaves are the offer `hash` values as `bytes32` and are deterministically
4431
- * ordered following the StandardMerkleTree leaf ordering so that the resulting
4432
- * root is stable regardless of the input order.
4654
+ * ordered so that the resulting root is stable regardless of the input order.
4433
4655
  *
4434
4656
  * @param offers - Offers to include in the tree.
4435
- * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
4657
+ * @returns A `SimpleMerkleTree` of offer hashes representing the offers.
4436
4658
  * @throws {TreeError} If tree building fails due to offer inconsistencies.
4437
4659
  */
4438
4660
  const from$1 = (offers) => {
4439
- const leaves = offers.map((offer) => [hash(offer)]);
4440
- const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
4661
+ assertUniqueOfferHashes(offers, (reason) => new TreeError(reason));
4662
+ const leaves = offers.map((offer) => hash(offer));
4663
+ const tree = SimpleMerkleTree.of(leaves);
4441
4664
  const orderedOffers = orderOffers(tree, offers);
4442
4665
  return Object.assign(tree, { offers: orderedOffers });
4443
4666
  };
4444
4667
  const orderOffers = (tree, offers) => {
4445
4668
  const offerByHash = /* @__PURE__ */ new Map();
4446
- for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
4669
+ for (const offer of offers) offerByHash.set(hash(offer), offer);
4447
4670
  const entries = tree.dump().values.map((value) => {
4448
- const hash = normalizeHash(value.value[0]);
4671
+ const hash = value.value;
4449
4672
  const offer = offerByHash.get(hash);
4450
4673
  if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
4451
4674
  return {
@@ -4460,7 +4683,7 @@ const orderOffers = (tree, offers) => {
4460
4683
  * Generates merkle proofs for all offers in a tree.
4461
4684
  *
4462
4685
  * Each proof allows independent verification that an offer is included in the tree
4463
- * without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
4686
+ * without requiring the full tree.
4464
4687
  *
4465
4688
  * @param tree - The {@link Tree} to generate proofs for.
4466
4689
  * @returns Array of proofs - {@link Proof}
@@ -4469,7 +4692,7 @@ const proofs = (tree) => {
4469
4692
  return tree.offers.map((offer) => {
4470
4693
  return {
4471
4694
  offer,
4472
- path: tree.getProof([hash(offer)])
4695
+ path: tree.getProof(hash(offer))
4473
4696
  };
4474
4697
  });
4475
4698
  };
@@ -4601,14 +4824,15 @@ const encodeUnsigned = (tree) => {
4601
4824
  };
4602
4825
  const validateTreeForEncoding = (tree) => {
4603
4826
  if (VERSION$1 > 255) throw new EncodeError(`version overflow: ${VERSION$1} exceeds 255`);
4827
+ if (tree.offers.length > MAX_OFFERS_PER_TREE) throw new EncodeError(`offers payload exceeds ${MAX_OFFERS_PER_TREE} offers`);
4604
4828
  const computed = from$1(tree.offers);
4605
4829
  if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
4606
4830
  };
4607
4831
  const encodeUnsignedBytes = (tree) => {
4608
4832
  const offersPayload = tree.offers.map(serialize);
4609
- const compressed = gzip(JSON.stringify(offersPayload));
4833
+ const compressed = gzipOffersPayload(JSON.stringify(offersPayload), (reason) => new EncodeError(reason));
4610
4834
  const rootBytes = hexToBytes(tree.root);
4611
- const encoded = new Uint8Array(1 + compressed.length + 32);
4835
+ const encoded = new Uint8Array(1 + compressed.length + ROOT_BYTES);
4612
4836
  encoded[0] = VERSION$1;
4613
4837
  encoded.set(compressed, 1);
4614
4838
  encoded.set(rootBytes, 1 + compressed.length);
@@ -4621,10 +4845,11 @@ const encodeUnsignedBytes = (tree) => {
4621
4845
  * Returns the tree with separately validated signature and recovered signer address.
4622
4846
  *
4623
4847
  * Validation order:
4624
- * 1. Version check
4848
+ * 1. Version and static size checks
4625
4849
  * 2. Signature verification (fail-fast, before decompression)
4626
- * 3. Decompression (only if signature valid)
4627
- * 4. Root verification (computed from offers vs embedded root)
4850
+ * 3. Streaming decompression with byte cap
4851
+ * 4. JSON array + offer count checks
4852
+ * 5. Root verification (computed from offers vs embedded root)
4628
4853
  *
4629
4854
  * @example
4630
4855
  * ```typescript
@@ -4641,33 +4866,20 @@ const decode = async (encoded, domain) => {
4641
4866
  const errorFactory = (reason) => new DecodeError(reason);
4642
4867
  const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
4643
4868
  const bytes = hexToBytes(encoded);
4644
- if (bytes.length < 98) throw new DecodeError("payload too short");
4869
+ if (bytes.length < MIN_SIGNED_PAYLOAD_BYTES) throw new DecodeError("payload too short");
4645
4870
  const version = bytes[0];
4646
4871
  if (version !== (VERSION$1 & 255)) throw new DecodeError(`invalid version: expected ${VERSION$1}, got ${version ?? 0}`);
4647
- const signature = bytesToHex(bytes.slice(-65));
4648
- const root = bytesToHex(bytes.slice(-97, -65));
4649
- assertHex(root, 32, "root");
4650
- assertHex(signature, 65, "signature");
4872
+ const signature = bytesToHex(bytes.slice(-SIGNATURE_BYTES));
4873
+ const root = bytesToHex(bytes.slice(-(ROOT_BYTES + SIGNATURE_BYTES), -SIGNATURE_BYTES));
4874
+ assertHex(root, ROOT_BYTES, "root");
4875
+ assertHex(signature, SIGNATURE_BYTES, "signature");
4651
4876
  const signer = await verifySignatureAndRecoverAddress({
4652
4877
  root,
4653
4878
  signature,
4654
4879
  domain: normalizedDomain,
4655
4880
  errorFactory
4656
4881
  });
4657
- const compressed = bytes.slice(1, -97);
4658
- let decoded;
4659
- try {
4660
- decoded = ungzip(compressed, { to: "string" });
4661
- } catch {
4662
- throw new DecodeError("decompression failed");
4663
- }
4664
- let rawOffers;
4665
- try {
4666
- rawOffers = JSON.parse(decoded);
4667
- } catch {
4668
- throw new DecodeError("JSON parse failed");
4669
- }
4670
- const tree = from$1(rawOffers.map((o) => OfferSchema().parse(o)));
4882
+ const tree = from$1(parseRawOffersPayload(gunzipOffersPayload(bytes.slice(1, -(ROOT_BYTES + SIGNATURE_BYTES)), errorFactory), errorFactory).map((o) => OfferSchema().parse(o)));
4671
4883
  if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
4672
4884
  return {
4673
4885
  tree,
@@ -4786,11 +4998,10 @@ async function getOffers(apiClient, parameters) {
4786
4998
  return {
4787
4999
  ...fromSnakeCase$1({
4788
5000
  maker: offerData.maker,
4789
- assets: offerData.assets,
4790
- obligation_units: offerData.obligation_units,
4791
- obligation_shares: offerData.obligation_shares,
5001
+ max_units: offerData.max_units,
4792
5002
  tick: offerData.tick,
4793
5003
  maturity: from$9(offerData.obligation.maturity),
5004
+ rcf_threshold: offerData.obligation.rcf_threshold,
4794
5005
  expiry: offerData.expiry,
4795
5006
  start: offerData.start,
4796
5007
  group: offerData.group,
@@ -4800,13 +5011,15 @@ async function getOffers(apiClient, parameters) {
4800
5011
  collaterals: offerData.obligation.collaterals.map((collateral) => ({
4801
5012
  asset: collateral.token,
4802
5013
  oracle: collateral.oracle,
4803
- lltv: collateral.lltv
5014
+ lltv: collateral.lltv,
5015
+ max_lif: collateral.max_lif
4804
5016
  })),
4805
5017
  callback: {
4806
5018
  address: offerData.callback,
4807
5019
  data: offerData.callback_data
4808
5020
  },
4809
- receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller
5021
+ receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller,
5022
+ exit_only: offerData.exit_only ?? false
4810
5023
  }),
4811
5024
  hash: item.offer_hash,
4812
5025
  consumed: BigInt(item.consumed),
@@ -4847,9 +5060,11 @@ async function getObligations(apiClient, parameters) {
4847
5060
  collaterals: item.collaterals.map((collateral) => ({
4848
5061
  asset: collateral.token,
4849
5062
  oracle: collateral.oracle,
4850
- lltv: collateral.lltv
5063
+ lltv: collateral.lltv,
5064
+ max_lif: collateral.max_lif
4851
5065
  })),
4852
- maturity: from$9(item.maturity)
5066
+ maturity: from$9(item.maturity),
5067
+ rcf_threshold: item.rcf_threshold
4853
5068
  });
4854
5069
  const { obligationId: _, ...quote } = from$4({
4855
5070
  obligationId: item.id,
@@ -5140,7 +5355,6 @@ const assets = {
5140
5355
  "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
5141
5356
  "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
5142
5357
  "0x4200000000000000000000000000000000000006",
5143
- "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
5144
5358
  "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
5145
5359
  "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
5146
5360
  "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
@@ -5337,6 +5551,34 @@ function lazy(pollFn) {
5337
5551
  })();
5338
5552
  }
5339
5553
 
5554
+ //#endregion
5555
+ //#region src/utils/mapWithConcurrency.ts
5556
+ /**
5557
+ * Map values with a bounded number of concurrent async workers.
5558
+ *
5559
+ * Result ordering always matches the input order.
5560
+ * @param parameters - Input values, concurrency limit, and async mapper.
5561
+ * @returns Mapped results in input order.
5562
+ */
5563
+ async function mapWithConcurrency(parameters) {
5564
+ const { values, limit, run } = parameters;
5565
+ if (values.length === 0) return [];
5566
+ const normalizedLimit = Math.max(1, Math.floor(limit));
5567
+ const workerCount = Math.min(normalizedLimit, values.length);
5568
+ const results = new Array(values.length);
5569
+ let nextIndex = 0;
5570
+ const worker = async () => {
5571
+ while (true) {
5572
+ const index = nextIndex;
5573
+ if (index >= values.length) return;
5574
+ nextIndex += 1;
5575
+ results[index] = await run(values[index], index);
5576
+ }
5577
+ };
5578
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
5579
+ return results;
5580
+ }
5581
+
5340
5582
  //#endregion
5341
5583
  //#region src/utils/wait.ts
5342
5584
  async function wait(time) {
@@ -5378,6 +5620,20 @@ function max() {
5378
5620
  return 0x77e772392b600000;
5379
5621
  }
5380
5622
 
5623
+ //#endregion
5624
+ //#region src/utils/trim.ts
5625
+ /**
5626
+ * Keep the last `keep` entries from an array.
5627
+ * @param array - Source array.
5628
+ * @param keep - Number of entries to keep.
5629
+ * @returns Trimmed copy.
5630
+ */
5631
+ const trimTail = (array, keep) => {
5632
+ if (!Number.isInteger(keep) || keep < 0) throw new Error(`trimTail: expected non-negative integer keep, got ${keep}`);
5633
+ if (array.length <= keep) return array.slice();
5634
+ return array.slice(array.length - keep);
5635
+ };
5636
+
5381
5637
  //#endregion
5382
5638
  //#region src/utils/index.ts
5383
5639
  var utils_exports = /* @__PURE__ */ __exportAll({
@@ -5391,18 +5647,20 @@ var utils_exports = /* @__PURE__ */ __exportAll({
5391
5647
  batchMulticall: () => batchMulticall,
5392
5648
  fromSnakeCase: () => fromSnakeCase$3,
5393
5649
  lazy: () => lazy,
5650
+ mapWithConcurrency: () => mapWithConcurrency,
5394
5651
  max: () => max$1,
5395
5652
  min: () => min,
5396
5653
  poll: () => poll,
5397
5654
  retry: () => retry,
5398
5655
  stringifyBigint: () => stringifyBigint,
5399
5656
  toSnakeCase: () => toSnakeCase$1,
5657
+ trimTail: () => trimTail,
5400
5658
  wait: () => wait
5401
5659
  });
5402
5660
 
5403
5661
  //#endregion
5404
5662
  //#region src/database/drizzle/VERSION.ts
5405
- const VERSION = "router_v1.13";
5663
+ const VERSION = "router_v1.16";
5406
5664
 
5407
5665
  //#endregion
5408
5666
  //#region src/database/drizzle/schema.ts
@@ -5422,6 +5680,7 @@ var EnumTableName = /* @__PURE__ */ function(EnumTableName) {
5422
5680
  EnumTableName["VALIDATIONS"] = "validations";
5423
5681
  EnumTableName["COLLECTORS"] = "collectors";
5424
5682
  EnumTableName["CHAINS"] = "chains";
5683
+ EnumTableName["PENDING_LINKS"] = "pending_links";
5425
5684
  EnumTableName["LOTS"] = "lots";
5426
5685
  EnumTableName["LOTS_POSITIONS"] = "lots_positions";
5427
5686
  EnumTableName["OFFSETS"] = "offsets";
@@ -5434,10 +5693,14 @@ const VERSIONED_TABLE_NAMES = TABLE_NAMES.map((table) => `"${VERSION}"."${table}
5434
5693
  const obligations = s.table(EnumTableName.OBLIGATIONS, {
5435
5694
  obligationKey: varchar("obligation_key", { length: 66 }).primaryKey(),
5436
5695
  loanToken: varchar("loan_token", { length: 42 }).notNull(),
5437
- maturity: integer("maturity").notNull()
5696
+ maturity: integer("maturity").notNull(),
5697
+ rcfThreshold: numeric("rcf_threshold", {
5698
+ precision: 78,
5699
+ scale: 0
5700
+ }).notNull()
5438
5701
  });
5439
5702
  const obligationIdKeys = s.table(EnumTableName.OBLIGATION_ID_KEYS, {
5440
- obligationId: varchar("obligation_id", { length: 42 }).primaryKey(),
5703
+ obligationId: varchar("obligation_id", { length: 66 }).primaryKey(),
5441
5704
  obligationKey: varchar("obligation_key", { length: 66 }).notNull().references(() => obligations.obligationKey, { onDelete: "cascade" }),
5442
5705
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5443
5706
  morphoV2: varchar("morpho_v2", { length: 42 }).notNull()
@@ -5459,7 +5722,7 @@ const groups = s.table(EnumTableName.GROUPS, {
5459
5722
  table.group
5460
5723
  ],
5461
5724
  name: "groups_pk"
5462
- }), index("groups_chain_id_maker_group_consumed_idx").on(table.chainId, table.maker, table.group, table.consumed)]);
5725
+ })]);
5463
5726
  const consumedEvents = s.table(EnumTableName.CONSUMED_EVENTS, {
5464
5727
  eventId: varchar("event_id", { length: 128 }).primaryKey(),
5465
5728
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
@@ -5493,16 +5756,13 @@ const obligationCollateralsV2 = s.table(EnumTableName.OBLIGATION_COLLATERALS_V2,
5493
5756
  asset: varchar("asset", { length: 42 }).notNull(),
5494
5757
  oracleAddress: varchar("oracle_address", { length: 42 }).notNull(),
5495
5758
  lltv: bigint("lltv", { mode: "bigint" }).notNull(),
5759
+ maxLif: bigint("max_lif", { mode: "bigint" }).notNull(),
5496
5760
  collateralIndex: integer("collateral_index").notNull(),
5497
5761
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5498
- }, (table) => [
5499
- primaryKey({
5500
- columns: [table.obligationKey, table.asset],
5501
- name: "obligation_collaterals_v2_pk"
5502
- }),
5503
- index("obligation_collaterals_v2_obligation_key_idx").on(table.obligationKey),
5504
- index("obligation_collaterals_v2_oracle_address_idx").on(table.oracleAddress)
5505
- ]);
5762
+ }, (table) => [primaryKey({
5763
+ columns: [table.obligationKey, table.asset],
5764
+ name: "obligation_collaterals_v2_pk"
5765
+ })]);
5506
5766
  const oracles = s.table(EnumTableName.ORACLES, {
5507
5767
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5508
5768
  address: varchar("address", { length: 42 }).notNull(),
@@ -5518,16 +5778,8 @@ const oracles = s.table(EnumTableName.ORACLES, {
5518
5778
  })]);
5519
5779
  const offers = s.table(EnumTableName.OFFERS, {
5520
5780
  hash: varchar("hash", { length: 66 }).notNull(),
5521
- obligationId: varchar("obligation_id", { length: 42 }).notNull().references(() => obligationIdKeys.obligationId, { onDelete: "cascade" }),
5522
- assets: numeric("assets", {
5523
- precision: 78,
5524
- scale: 0
5525
- }).notNull(),
5526
- obligationUnits: numeric("obligation_units", {
5527
- precision: 78,
5528
- scale: 0
5529
- }).notNull().default("0"),
5530
- obligationShares: numeric("obligation_shares", {
5781
+ obligationId: varchar("obligation_id", { length: 66 }).notNull().references(() => obligationIdKeys.obligationId, { onDelete: "cascade" }),
5782
+ maxUnits: numeric("max_units", {
5531
5783
  precision: 78,
5532
5784
  scale: 0
5533
5785
  }).notNull().default("0"),
@@ -5543,6 +5795,7 @@ const offers = s.table(EnumTableName.OFFERS, {
5543
5795
  callbackAddress: varchar("callback_address", { length: 42 }).notNull(),
5544
5796
  callbackData: text("callback_data").notNull(),
5545
5797
  receiverIfMakerIsSeller: varchar("receiver_if_maker_is_seller", { length: 42 }),
5798
+ exitOnly: boolean("exit_only").notNull().default(false),
5546
5799
  blockNumber: bigint("block_number", { mode: "number" }).notNull(),
5547
5800
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5548
5801
  }, (table) => [
@@ -5563,13 +5816,16 @@ const offers = s.table(EnumTableName.OFFERS, {
5563
5816
  ],
5564
5817
  name: "offers_groups_fk"
5565
5818
  }).onDelete("cascade"),
5566
- index("offers_group_fk_idx").on(table.groupChainId, table.groupMaker, table.group),
5567
5819
  index("offers_group_and_hash_idx").on(table.groupChainId, table.groupMaker, table.group, table.hash),
5568
- index("offers_obligation_id_side_idx").on(table.obligationId, table.buy)
5820
+ index("offers_obligation_side_tick_idx").on(table.obligationId, table.buy, table.tick),
5821
+ index("offers_obligation_active_tick_idx").on(table.obligationId, table.buy, table.expiry, table.maturity, table.start, table.tick),
5822
+ index("offers_group_maker_idx").on(table.groupMaker, table.hash, table.obligationId),
5823
+ index("offers_group_winner_expr_idx").on(table.groupChainId, table.groupMaker, table.group, table.obligationId, table.buy, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"max_units" DESC`, table.hash),
5824
+ index("offers_book_winners_covering_idx").on(table.obligationId, table.buy, table.groupChainId, table.groupMaker, table.group, sql`(CASE WHEN "buy" THEN -"tick" ELSE "tick" END)`, table.blockNumber, sql`"max_units" DESC`, table.hash)
5569
5825
  ]);
5570
5826
  const offersCallbacks = s.table(EnumTableName.OFFERS_CALLBACKS, {
5571
5827
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5572
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5828
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5573
5829
  callbackId: varchar("callback_id", { length: 66 })
5574
5830
  }, (table) => [foreignKey({
5575
5831
  columns: [table.offerHash, table.obligationId],
@@ -5610,7 +5866,7 @@ const lots = s.table(EnumTableName.LOTS, {
5610
5866
  user: varchar("user", { length: 42 }).notNull(),
5611
5867
  contract: varchar("contract", { length: 66 }).notNull(),
5612
5868
  group: varchar("group", { length: 66 }).notNull(),
5613
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5869
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5614
5870
  lower: numeric("lower", {
5615
5871
  precision: 78,
5616
5872
  scale: 0
@@ -5655,40 +5911,45 @@ const lots = s.table(EnumTableName.LOTS, {
5655
5911
  groups.group
5656
5912
  ],
5657
5913
  name: "lots_groups_fk"
5658
- }).onDelete("cascade")
5914
+ }).onDelete("cascade"),
5915
+ index("lots_position_group_obligation_idx").on(table.chainId, table.user, table.group, table.obligationId)
5659
5916
  ]);
5660
5917
  const offsets = s.table(EnumTableName.OFFSETS, {
5661
5918
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5662
5919
  user: varchar("user", { length: 42 }).notNull(),
5663
5920
  contract: varchar("contract", { length: 66 }).notNull(),
5664
5921
  group: varchar("group", { length: 66 }).notNull(),
5665
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5922
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5666
5923
  value: numeric("value", {
5667
5924
  precision: 78,
5668
5925
  scale: 0
5669
5926
  }).notNull()
5670
- }, (table) => [primaryKey({
5671
- columns: [
5672
- table.chainId,
5673
- table.user,
5674
- table.contract,
5675
- table.group,
5676
- table.obligationId
5677
- ],
5678
- name: "offsets_pk"
5679
- }), foreignKey({
5680
- columns: [
5681
- table.chainId,
5682
- table.contract,
5683
- table.user
5684
- ],
5685
- foreignColumns: [
5686
- lotsPositions.chainId,
5687
- lotsPositions.contract,
5688
- lotsPositions.user
5689
- ],
5690
- name: "offsets_lots_positions_fk"
5691
- }).onDelete("cascade")]);
5927
+ }, (table) => [
5928
+ primaryKey({
5929
+ columns: [
5930
+ table.chainId,
5931
+ table.user,
5932
+ table.contract,
5933
+ table.group,
5934
+ table.obligationId
5935
+ ],
5936
+ name: "offsets_pk"
5937
+ }),
5938
+ foreignKey({
5939
+ columns: [
5940
+ table.chainId,
5941
+ table.contract,
5942
+ table.user
5943
+ ],
5944
+ foreignColumns: [
5945
+ lotsPositions.chainId,
5946
+ lotsPositions.contract,
5947
+ lotsPositions.user
5948
+ ],
5949
+ name: "offsets_lots_positions_fk"
5950
+ }).onDelete("cascade"),
5951
+ index("offsets_position_obligation_idx").on(table.chainId, table.contract, table.user, table.obligationId)
5952
+ ]);
5692
5953
  const PositionTypes = s.enum("position_type", Object.values(Type));
5693
5954
  const positionTypes = s.table("position_types", {
5694
5955
  id: serial("id").primaryKey(),
@@ -5775,7 +6036,7 @@ const status = s.table("status", {
5775
6036
  });
5776
6037
  const validations = s.table("validations", {
5777
6038
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5778
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
6039
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5779
6040
  statusId: integer("status_id").notNull().references(() => status.id, { onDelete: "no action" }),
5780
6041
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5781
6042
  }, (table) => [primaryKey({
@@ -5803,8 +6064,33 @@ const chains = s.table(EnumTableName.CHAINS, {
5803
6064
  precision: 78,
5804
6065
  scale: 0
5805
6066
  }).default("0").notNull(),
6067
+ checkpoints: text("checkpoints").default("[]").notNull(),
6068
+ tipHash: text("tip_hash"),
6069
+ finalizedBlockNumber: bigint("finalized_block_number", { mode: "number" }),
6070
+ finalizedBlockHash: text("finalized_block_hash"),
5806
6071
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5807
6072
  }, (table) => [uniqueIndex("chains_chain_id_idx").on(table.chainId)]);
6073
+ const pendingLinks = s.table(EnumTableName.PENDING_LINKS, {
6074
+ key: varchar("key", { length: 191 }).primaryKey(),
6075
+ type: text("type").notNull(),
6076
+ status: text("status").notNull(),
6077
+ chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
6078
+ eventId: varchar("event_id", { length: 128 }).notNull(),
6079
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
6080
+ collateralIndex: integer("collateral_index").notNull(),
6081
+ user: varchar("user", { length: 42 }).notNull(),
6082
+ amount: numeric("amount", {
6083
+ precision: 78,
6084
+ scale: 0
6085
+ }).notNull(),
6086
+ blockNumber: bigint("block_number", { mode: "number" }).notNull(),
6087
+ firstSeenBlock: bigint("first_seen_block", { mode: "number" }).notNull(),
6088
+ lastTriedBlock: bigint("last_tried_block", { mode: "number" }),
6089
+ attempts: integer("attempts").notNull().default(0),
6090
+ ignoredReason: text("ignored_reason"),
6091
+ resolvedAt: timestamp("resolved_at"),
6092
+ updatedAt: timestamp("updated_at").defaultNow().notNull()
6093
+ }, (table) => [index("pending_links_pending_scan_idx").on(table.chainId, table.type, table.status, table.firstSeenBlock), index("pending_links_event_id_idx").on(table.chainId, table.eventId)]);
5808
6094
  const trees = s.table(EnumTableName.TREES, {
5809
6095
  root: varchar("root", { length: 66 }).primaryKey(),
5810
6096
  rootSignature: varchar("root_signature", { length: 132 }).notNull(),
@@ -5812,7 +6098,7 @@ const trees = s.table(EnumTableName.TREES, {
5812
6098
  });
5813
6099
  const merklePaths = s.table(EnumTableName.MERKLE_PATHS, {
5814
6100
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5815
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
6101
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5816
6102
  treeRoot: varchar("tree_root", { length: 66 }).notNull().references(() => trees.root, { onDelete: "cascade" }),
5817
6103
  proofNodes: text("proof_nodes").notNull(),
5818
6104
  createdAt: timestamp("created_at").defaultNow().notNull()
@@ -5839,7 +6125,7 @@ function compositeKey(g) {
5839
6125
  //#endregion
5840
6126
  //#region src/gatekeeper/Rules.ts
5841
6127
  var Rules_exports = /* @__PURE__ */ __exportAll({
5842
- amountMutualExclusivity: () => amountMutualExclusivity,
6128
+ amountNonZero: () => amountNonZero,
5843
6129
  callback: () => callback,
5844
6130
  collateralToken: () => collateralToken,
5845
6131
  groupConsistency: () => groupConsistency,
@@ -5910,11 +6196,6 @@ const sameMaker = () => batch("mixed_maker", "Validates that all offers in a bat
5910
6196
  return issues;
5911
6197
  });
5912
6198
  /**
5913
- * A validation rule that ensures mutual exclusivity of offer amount fields.
5914
- * At most one of (assets, obligationUnits, obligationShares) can be non-zero.
5915
- * Matches contract requirement: `atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)`.
5916
- */
5917
- /**
5918
6199
  * A validation rule that checks if the offer duration (expiry - start) meets a minimum threshold.
5919
6200
  * @param minSeconds - Minimum required duration in seconds.
5920
6201
  * @returns The issue that was found. If the offer is valid, this will be undefined.
@@ -5932,14 +6213,20 @@ const minDuration = ({ minSeconds }) => single("min_duration", `Validates that o
5932
6213
  const maxCollaterals = ({ max }) => single("max_collaterals", `Validates that an offer has at most ${max} collaterals`, (offer) => {
5933
6214
  if (offer.collaterals.length > max) return { message: `Offer has ${offer.collaterals.length} collaterals, exceeding the maximum of ${max}` };
5934
6215
  });
5935
- const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Validates that at most one of (assets, obligationUnits, obligationShares) is non-zero", (offer) => {
5936
- if (!atMostOneNonZero(offer.assets, offer.obligationUnits, offer.obligationShares)) return { message: "Inconsistent offer input: at most one of (assets, obligationUnits, obligationShares) must be non-zero" };
6216
+ /**
6217
+ * A validation rule that checks if the offer's maxUnits is non-zero.
6218
+ * The contract requires a positive amount; this rule rejects early.
6219
+ * @returns The issue that was found. If the offer is valid, this will be undefined.
6220
+ */
6221
+ const amountNonZero = () => single("amount_non_zero", "Validates that maxUnits is non-zero", (offer) => {
6222
+ if (offer.maxUnits === 0n) return { message: "maxUnits must be non-zero" };
5937
6223
  });
5938
6224
  /**
5939
6225
  * A batch validation rule that ensures all offers within the same group are consistent.
5940
- * All offers sharing the same group must have the same loan token, assets amount, and side (buy/sell).
6226
+ * All offers sharing the same group must have the same loan token, maxUnits,
6227
+ * and side (buy/sell). The contract tracks consumed per group and requires these to match.
5941
6228
  */
5942
- const groupConsistency = () => batch("group_consistency", "Validates that all offers in a group have the same loan token, assets amount, and side", (offers) => {
6229
+ const groupConsistency = () => batch("group_consistency", "Validates that all offers in a group have the same loan token, obligation amounts, and side", (offers) => {
5943
6230
  const issues = /* @__PURE__ */ new Map();
5944
6231
  if (offers.length === 0) return issues;
5945
6232
  const groupMap = /* @__PURE__ */ new Map();
@@ -5953,13 +6240,13 @@ const groupConsistency = () => batch("group_consistency", "Validates that all of
5953
6240
  if (indices.length <= 1) continue;
5954
6241
  const reference = offers[indices[0]];
5955
6242
  const refLoanToken = reference.loanToken.toLowerCase();
5956
- const refAssets = reference.assets;
6243
+ const refUnits = reference.maxUnits;
5957
6244
  const refBuy = reference.buy;
5958
6245
  for (let j = 1; j < indices.length; j++) {
5959
6246
  const idx = indices[j];
5960
6247
  const offer = offers[idx];
5961
6248
  if (offer.loanToken.toLowerCase() !== refLoanToken) issues.set(idx, { message: `All offers in a group must have the same loan token. Expected ${reference.loanToken}, got ${offer.loanToken}` });
5962
- else if (offer.assets !== refAssets) issues.set(idx, { message: `All offers in a group must have the same assets amount. Expected ${refAssets}, got ${offer.assets}` });
6249
+ else if (offer.maxUnits !== refUnits) issues.set(idx, { message: `All offers in a group must have the same maxUnits. Expected ${refUnits}, got ${offer.maxUnits}` });
5963
6250
  else if (offer.buy !== refBuy) issues.set(idx, { message: `All offers in a group must be on the same side. Expected ${refBuy ? "buy" : "sell"}, got ${offer.buy ? "buy" : "sell"}` });
5964
6251
  }
5965
6252
  }
@@ -6016,7 +6303,7 @@ const morphoRules = (parameters) => {
6016
6303
  }
6017
6304
  const rules = [
6018
6305
  sameMaker(),
6019
- amountMutualExclusivity(),
6306
+ amountNonZero(),
6020
6307
  groupConsistency(),
6021
6308
  ...config?.minDuration != null ? [minDuration({ minSeconds: config.minDuration })] : [],
6022
6309
  maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),