@morpho-dev/router 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +20 -5
  2. package/dist/cli.js +11700 -6794
  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/meta/0036_snapshot.json +1864 -0
  20. package/dist/drizzle/migrations/meta/0037_snapshot.json +1876 -0
  21. package/dist/drizzle/migrations/meta/0038_snapshot.json +1882 -0
  22. package/dist/drizzle/migrations/meta/0039_snapshot.json +1960 -0
  23. package/dist/drizzle/migrations/meta/0040_snapshot.json +1912 -0
  24. package/dist/drizzle/migrations/meta/0041_snapshot.json +1912 -0
  25. package/dist/drizzle/migrations/meta/0042_snapshot.json +1882 -0
  26. package/dist/drizzle/migrations/meta/0043_snapshot.json +1909 -0
  27. package/dist/drizzle/migrations/meta/0044_snapshot.json +1853 -0
  28. package/dist/drizzle/migrations/meta/0045_snapshot.json +1921 -0
  29. package/dist/drizzle/migrations/meta/0046_snapshot.json +1966 -0
  30. package/dist/drizzle/migrations/meta/0047_snapshot.json +2005 -0
  31. package/dist/drizzle/migrations/meta/0048_snapshot.json +2035 -0
  32. package/dist/drizzle/migrations/meta/0049_snapshot.json +2035 -0
  33. package/dist/drizzle/migrations/meta/_journal.json +112 -0
  34. package/dist/evm/bytecode/morpho.txt +1 -1
  35. package/dist/index.browser.d.mts +587 -271
  36. package/dist/index.browser.d.mts.map +1 -1
  37. package/dist/index.browser.mjs +656 -419
  38. package/dist/index.browser.mjs.map +1 -1
  39. package/dist/index.node.d.mts +1454 -583
  40. package/dist/index.node.d.mts.map +1 -1
  41. package/dist/index.node.mjs +9064 -5228
  42. package/dist/index.node.mjs.map +1 -1
  43. package/dist/server-D4xxddev.js +9573 -0
  44. package/dist/server.js +9617 -0
  45. package/docs/integrator.md +14 -24
  46. 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,6 +77,8 @@ var Tick_exports = /* @__PURE__ */ __exportAll({
77
77
  InvalidTickError: () => InvalidTickError,
78
78
  MAX_PRICE: () => MAX_PRICE,
79
79
  TICK_RANGE: () => TICK_RANGE,
80
+ assetsToObligationUnits: () => assetsToObligationUnits,
81
+ obligationUnitsToAssets: () => obligationUnitsToAssets,
80
82
  priceToTick: () => priceToTick,
81
83
  tickToPrice: () => tickToPrice
82
84
  });
@@ -136,6 +138,26 @@ 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 obligation units to assets using the tick price (mulDivDown).
143
+ * @param obligationUnits - The obligation units to convert.
144
+ * @param tick - The offer tick.
145
+ * @returns The equivalent amount in assets.
146
+ */
147
+ function obligationUnitsToAssets(obligationUnits, tick) {
148
+ return obligationUnits * tickToPrice(tick) / WAD$1;
149
+ }
150
+ /**
151
+ * Converts assets to obligation units using the tick price (mulDivUp).
152
+ * @param assets - The asset amount to convert.
153
+ * @param tick - The offer tick.
154
+ * @returns The equivalent amount in obligation units.
155
+ */
156
+ function assetsToObligationUnits(assets, tick) {
157
+ const price = tickToPrice(tick);
158
+ if (price === 0n) return 0n;
159
+ return (assets * WAD$1 + price - 1n) / price;
160
+ }
139
161
  var InvalidTickError = class extends BaseError {
140
162
  name = "Tick.InvalidTickError";
141
163
  constructor(tick) {
@@ -157,7 +179,7 @@ function from$15(level) {
157
179
  return {
158
180
  tick: level.tick,
159
181
  price: price.toString(),
160
- assets: level.assets.toString(),
182
+ obligation_units: level.obligationUnits.toString(),
161
183
  count: level.count
162
184
  };
163
185
  }
@@ -215,9 +237,11 @@ function from$14(obligation, quote, chainId) {
215
237
  collaterals: obligation.collaterals.map((c) => ({
216
238
  token: c.asset,
217
239
  lltv: c.lltv.toString(),
240
+ max_lif: c.maxLif.toString(),
218
241
  oracle: c.oracle
219
242
  })),
220
243
  maturity: obligation.maturity,
244
+ rcf_threshold: obligation.rcfThreshold.toString(),
221
245
  ask: {
222
246
  tick: quote.ask.tick,
223
247
  price: quote.ask.price.toString()
@@ -258,15 +282,15 @@ function from$13(input) {
258
282
  collaterals: input.collaterals.map((c) => ({
259
283
  token: c.asset,
260
284
  lltv: c.lltv.toString(),
285
+ max_lif: c.maxLif.toString(),
261
286
  oracle: c.oracle
262
287
  })),
263
- maturity: input.maturity
288
+ maturity: input.maturity,
289
+ rcf_threshold: input.rcfThreshold.toString()
264
290
  },
265
291
  buy: input.buy,
266
292
  maker: input.maker,
267
- assets: input.assets.toString(),
268
293
  obligation_units: input.obligationUnits.toString(),
269
- obligation_shares: input.obligationShares.toString(),
270
294
  start: input.start,
271
295
  expiry: input.expiry,
272
296
  tick: input.tick,
@@ -274,7 +298,8 @@ function from$13(input) {
274
298
  session: input.session,
275
299
  callback: input.callback.address,
276
300
  callback_data: input.callback.data,
277
- receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
301
+ receiver_if_maker_is_seller: input.receiverIfMakerIsSeller,
302
+ exit_only: input.exitOnly
278
303
  },
279
304
  offer_hash: input.hash,
280
305
  obligation_id: input.obligationId,
@@ -327,15 +352,15 @@ const offerExample = {
327
352
  collaterals: [{
328
353
  token: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
329
354
  lltv: "860000000000000000",
355
+ max_lif: "0",
330
356
  oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
331
357
  }],
332
- maturity: 1761922799
358
+ maturity: 1761922799,
359
+ rcf_threshold: "0"
333
360
  },
334
361
  buy: false,
335
362
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
336
- assets: "369216000000000000000000",
337
- obligation_units: "0",
338
- obligation_shares: "0",
363
+ obligation_units: "369216000000000000000000",
339
364
  start: 1761922790,
340
365
  expiry: 1761922799,
341
366
  tick: 495,
@@ -343,7 +368,8 @@ const offerExample = {
343
368
  session: "0x0000000000000000000000000000000000000000000000000000000000000000",
344
369
  callback: "0x0000000000000000000000000000000000000000",
345
370
  callback_data: "0x",
346
- receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
371
+ receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
372
+ exit_only: false
347
373
  },
348
374
  offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
349
375
  obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf79",
@@ -377,11 +403,10 @@ const missingCollectorExample = {
377
403
  };
378
404
  const validateOfferExample = {
379
405
  maker: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
380
- assets: "369216000000000000000000",
381
- obligation_units: "0",
382
- obligation_shares: "0",
406
+ obligation_units: "369216000000000000000000",
383
407
  tick: 495,
384
408
  maturity: 1761922799,
409
+ rcf_threshold: "0",
385
410
  expiry: 1761922799,
386
411
  start: 1761922790,
387
412
  group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
@@ -392,13 +417,15 @@ const validateOfferExample = {
392
417
  collaterals: [{
393
418
  asset: "0x34Cf890dB685FC536E05652FB41f02090c3fb751",
394
419
  oracle: "0x45093658BE7f90B63D7c359e8f408e503c2D9401",
395
- lltv: "860000000000000000"
420
+ lltv: "860000000000000000",
421
+ max_lif: "0"
396
422
  }],
397
423
  callback: {
398
424
  address: "0x0000000000000000000000000000000000000000",
399
425
  data: "0x"
400
426
  },
401
- receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
427
+ receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
428
+ exit_only: false
402
429
  };
403
430
  const routerStatusExample = {
404
431
  status: "live",
@@ -442,6 +469,10 @@ __decorate([ApiProperty({
442
469
  type: "string",
443
470
  example: "860000000000000000"
444
471
  })], CollateralResponse.prototype, "lltv", void 0);
472
+ __decorate([ApiProperty({
473
+ type: "string",
474
+ example: "0"
475
+ })], CollateralResponse.prototype, "max_lif", void 0);
445
476
  __decorate([ApiProperty({
446
477
  type: "string",
447
478
  example: "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
@@ -459,6 +490,10 @@ __decorate([ApiProperty({
459
490
  type: "string",
460
491
  example: validateOfferExample.collaterals[0].lltv
461
492
  })], ValidateCollateralRequest.prototype, "lltv", void 0);
493
+ __decorate([ApiProperty({
494
+ type: "string",
495
+ example: validateOfferExample.collaterals[0].max_lif
496
+ })], ValidateCollateralRequest.prototype, "max_lif", void 0);
462
497
  var ValidateCallbackRequest = class {};
463
498
  __decorate([ApiProperty({
464
499
  type: "string",
@@ -503,6 +538,10 @@ __decorate([ApiProperty({
503
538
  type: "number",
504
539
  example: offerExample.offer.obligation.maturity
505
540
  })], ObligationOfferResponse.prototype, "maturity", void 0);
541
+ __decorate([ApiProperty({
542
+ type: "string",
543
+ example: offerExample.offer.obligation.rcf_threshold
544
+ })], ObligationOfferResponse.prototype, "rcf_threshold", void 0);
506
545
  var OfferDataResponse = class {};
507
546
  __decorate([ApiProperty({
508
547
  type: () => ObligationOfferResponse,
@@ -516,18 +555,10 @@ __decorate([ApiProperty({
516
555
  type: "string",
517
556
  example: offerExample.offer.maker
518
557
  })], OfferDataResponse.prototype, "maker", void 0);
519
- __decorate([ApiProperty({
520
- type: "string",
521
- example: offerExample.offer.assets
522
- })], OfferDataResponse.prototype, "assets", void 0);
523
558
  __decorate([ApiProperty({
524
559
  type: "string",
525
560
  example: offerExample.offer.obligation_units
526
561
  })], 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);
531
562
  __decorate([ApiProperty({
532
563
  type: "number",
533
564
  example: offerExample.offer.start
@@ -562,6 +593,10 @@ __decorate([ApiProperty({
562
593
  type: "string",
563
594
  example: offerExample.offer.receiver_if_maker_is_seller
564
595
  })], OfferDataResponse.prototype, "receiver_if_maker_is_seller", void 0);
596
+ __decorate([ApiProperty({
597
+ type: "boolean",
598
+ example: offerExample.offer.exit_only
599
+ })], OfferDataResponse.prototype, "exit_only", void 0);
565
600
  var OfferListItemResponse = class {};
566
601
  __decorate([ApiProperty({
567
602
  type: () => OfferDataResponse,
@@ -624,6 +659,10 @@ __decorate([ApiProperty({
624
659
  type: "number",
625
660
  example: 1761922800
626
661
  })], ObligationResponse.prototype, "maturity", void 0);
662
+ __decorate([ApiProperty({
663
+ type: "string",
664
+ example: "0"
665
+ })], ObligationResponse.prototype, "rcf_threshold", void 0);
627
666
  __decorate([ApiProperty({ type: () => AskResponse })], ObligationResponse.prototype, "ask", void 0);
628
667
  __decorate([ApiProperty({ type: () => BidResponse })], ObligationResponse.prototype, "bid", void 0);
629
668
  var ObligationListResponse = class extends SuccessResponse {};
@@ -771,20 +810,11 @@ __decorate([ApiProperty({
771
810
  type: "string",
772
811
  example: validateOfferExample.maker
773
812
  })], ValidateOfferRequest.prototype, "maker", void 0);
774
- __decorate([ApiProperty({
775
- type: "string",
776
- example: validateOfferExample.assets
777
- })], ValidateOfferRequest.prototype, "assets", void 0);
778
813
  __decorate([ApiProperty({
779
814
  type: "string",
780
815
  example: validateOfferExample.obligation_units,
781
816
  required: false
782
817
  })], ValidateOfferRequest.prototype, "obligation_units", void 0);
783
- __decorate([ApiProperty({
784
- type: "string",
785
- example: validateOfferExample.obligation_shares,
786
- required: false
787
- })], ValidateOfferRequest.prototype, "obligation_shares", void 0);
788
818
  __decorate([ApiProperty({
789
819
  type: "number",
790
820
  example: validateOfferExample.tick,
@@ -795,6 +825,10 @@ __decorate([ApiProperty({
795
825
  type: "number",
796
826
  example: validateOfferExample.maturity
797
827
  })], ValidateOfferRequest.prototype, "maturity", void 0);
828
+ __decorate([ApiProperty({
829
+ type: "string",
830
+ example: validateOfferExample.rcf_threshold
831
+ })], ValidateOfferRequest.prototype, "rcf_threshold", void 0);
798
832
  __decorate([ApiProperty({
799
833
  type: "number",
800
834
  example: validateOfferExample.expiry
@@ -831,6 +865,11 @@ __decorate([ApiProperty({
831
865
  type: "string",
832
866
  example: validateOfferExample.receiver_if_maker_is_seller
833
867
  })], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
868
+ __decorate([ApiProperty({
869
+ type: "boolean",
870
+ example: false,
871
+ required: false
872
+ })], ValidateOfferRequest.prototype, "exit_only", void 0);
834
873
  var ValidateOffersRequest = class {};
835
874
  __decorate([ApiProperty({
836
875
  type: "number",
@@ -909,7 +948,7 @@ __decorate([ApiProperty({
909
948
  __decorate([ApiProperty({
910
949
  type: "string",
911
950
  example: "369216000000000000000000"
912
- })], BookLevelResponse.prototype, "assets", void 0);
951
+ })], BookLevelResponse.prototype, "obligation_units", void 0);
913
952
  __decorate([ApiProperty({
914
953
  type: "number",
915
954
  example: 5
@@ -918,7 +957,7 @@ const positionExample = {
918
957
  chain_id: 1,
919
958
  contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
920
959
  user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
921
- obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf79",
960
+ obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
922
961
  reserved: "200000000000000000000",
923
962
  block_number: 21345678
924
963
  };
@@ -1533,7 +1572,7 @@ const OpenApi = async () => {
1533
1572
  info: {
1534
1573
  title: "Router API",
1535
1574
  version: "1.0.0",
1536
- description: "API for the Morpho Router"
1575
+ description: process.env.COMMIT_SHA ? `API for the Morpho Router — version: ${process.env.COMMIT_SHA.slice(0, 7)}` : "API for the Morpho Router"
1537
1576
  },
1538
1577
  servers: [{
1539
1578
  url: "https://router.morpho.dev",
@@ -1604,7 +1643,7 @@ function isValidOfferHashCursor(val) {
1604
1643
  return /^0x[a-f0-9]{64}$/i.test(val);
1605
1644
  }
1606
1645
  function isValidObligationIdCursor(val) {
1607
- return /^0x[a-f0-9]{40}$/i.test(val);
1646
+ return /^0x[a-f0-9]{64}$/i.test(val);
1608
1647
  }
1609
1648
  function isValidOfferCursor(val) {
1610
1649
  const [hash, obligationId, ...rest] = val.split(":");
@@ -1686,9 +1725,9 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
1686
1725
  description: "Side of the offer. Required when using obligation_id.",
1687
1726
  example: "buy"
1688
1727
  }),
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({
1728
+ 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
1729
  description: "Offers obligation id. Required when not using maker.",
1691
- example: "0x1234567890123456789012345678901234567890"
1730
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1692
1731
  }),
1693
1732
  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
1733
  description: "Maker address to filter offers by. Alternative to obligation_id + side.",
@@ -1773,9 +1812,9 @@ const GetObligationsQueryParams = z$1.object({
1773
1812
  example: "-ask,bid,maturity"
1774
1813
  })
1775
1814
  });
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({
1815
+ 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
1816
  description: "Obligation id",
1778
- example: "0x1234567890123456789012345678901234567890"
1817
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1779
1818
  }) });
1780
1819
  /** Validate a book cursor format: {side, lastTick, offersCursor} */
1781
1820
  function isValidBookCursor(cursorString) {
@@ -1810,9 +1849,9 @@ const HealthQueryParams = z$1.object({ strict: z$1.enum([
1810
1849
  }) });
1811
1850
  const GetBookParams = z$1.object({
1812
1851
  ...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({
1852
+ 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
1853
  description: "Obligation id",
1815
- example: "0x1234567890123456789012345678901234567890"
1854
+ example: "0x1234567890123456789012345678901234567890123456789012345678901234"
1816
1855
  }),
1817
1856
  side: z$1.enum(["buy", "sell"]).meta({
1818
1857
  description: "Side of the book (buy or sell).",
@@ -1900,57 +1939,75 @@ const MetaMorphoFactory = parseAbi(["event CreateMetaMorpho(address indexed meta
1900
1939
  //#region src/core/Abi/MorphoV2.ts
1901
1940
  const MorphoV2 = parseAbi([
1902
1941
  "constructor()",
1903
- "function collateralOf(bytes20 id, address user, uint256 collateralIndex) view returns (uint128)",
1904
- "function consume(bytes32 group, uint256 amount)",
1942
+ "function activatedCollaterals(bytes32 id, address user) view returns (uint128)",
1943
+ "function collateralOf(bytes32 id, address user, uint256 index) view returns (uint128)",
1905
1944
  "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)",
1945
+ "function creditAfterSlashing(bytes32 id, address user) view returns (uint256)",
1946
+ "function creditOf(bytes32 id, address user) view returns (uint256)",
1947
+ "function debtOf(bytes32 id, address user) view returns (uint256)",
1948
+ "function defaultFees(address loanToken, uint256) view returns (uint16)",
1908
1949
  "function feeSetter() view returns (address)",
1909
- "function fees(bytes20 id) view returns (uint16[6])",
1950
+ "function fees(bytes32 id) view returns (uint16[7])",
1910
1951
  "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)",
1952
+ "function isAuthorized(address authorizer, address authorized) view returns (bool)",
1953
+ "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)",
1954
+ "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)",
1955
+ "function maxCollateralPerUser(address collateralToken) view returns (uint256)",
1956
+ "function maxLif(uint256 lltv, uint256 cursor) pure returns (uint256)",
1957
+ "function maxTakeableAssets(address loanToken) view returns (uint256)",
1958
+ "function maxTotalUnits(address loanToken) view returns (uint128)",
1959
+ "function maxTradingFee(uint256 index) pure returns (uint256)",
1913
1960
  "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)",
1961
+ "function obligationCreated(bytes32 id) view returns (bool)",
1962
+ "function obligationState(bytes32 id) view returns (uint128 totalUnits, uint256 withdrawable, uint128 lossIndex, bool created)",
1916
1963
  "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)",
1964
+ "function repay((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 obligationUnits, address onBehalf)",
1918
1965
  "function session(address user) view returns (bytes32)",
1966
+ "function setConsumed(bytes32 group, uint256 amount, address onBehalf)",
1919
1967
  "function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
1920
1968
  "function setFeeSetter(address newFeeSetter)",
1921
- "function setObligationTradingFee(bytes20 id, uint256 index, uint256 newTradingFee)",
1969
+ "function setIsAuthorized(address onBehalf, address authorized, bool newIsAuthorized)",
1970
+ "function setMaxCollateralPerUser(address collateralToken, uint256 newMaxCollateralPerUser)",
1971
+ "function setMaxTakeableAssets(address loanToken, uint256 newMaxTakeableAssets)",
1972
+ "function setMaxTotalUnits(address loanToken, uint128 newMaxTotalUnits)",
1973
+ "function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
1922
1974
  "function setOwner(address newOwner)",
1923
1975
  "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)",
1976
+ "function shuffleSession(address onBehalf)",
1977
+ "function slash(bytes32 id, address user)",
1978
+ "function supplyCollateral((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 collateralIndex, uint256 assets, address onBehalf)",
1979
+ "function take(uint256 obligationUnits, 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 obligationUnits, 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)",
1980
+ "function toId((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation) view returns (bytes32)",
1981
+ "function toObligation(bytes32 id) view returns ((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold))",
1982
+ "function totalUnits(bytes32 id) view returns (uint256)",
1983
+ "function touchObligation((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation) returns (bytes32)",
1984
+ "function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
1934
1985
  "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)",
1986
+ "function userLossIndex(bytes32 id, address user) view returns (uint128)",
1987
+ "function withdraw((address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation, uint256 obligationUnits, address onBehalf, address receiver)",
1988
+ "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)",
1989
+ "function withdrawable(bytes32 id) view returns (uint256)",
1938
1990
  "event Constructor(address indexed owner)",
1939
- "event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
1940
1991
  "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)",
1992
+ "event Liquidate(address indexed caller, bytes32 indexed id_, uint256 collateralIndex, uint256 seizedAssets, uint256 repaidUnits, address indexed borrower, uint256 badDebt, uint256 latestLossIndex)",
1993
+ "event ObligationCreated(bytes32 indexed id_, (address loanToken, (address token, uint256 lltv, uint256 maxLif, address oracle)[] collaterals, uint256 maturity, uint256 rcfThreshold) obligation)",
1994
+ "event Repay(address indexed caller, bytes32 indexed id_, uint256 obligationUnits, address indexed onBehalf)",
1995
+ "event SetConsumed(address indexed caller, address indexed onBehalf, bytes32 indexed group, uint256 amount)",
1944
1996
  "event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
1945
1997
  "event SetFeeSetter(address indexed feeSetter)",
1946
- "event SetObligationTradingFee(bytes20 indexed id_, uint256 indexed index, uint256 newTradingFee)",
1998
+ "event SetIsAuthorized(address indexed caller, address indexed onBehalf, address indexed authorized, bool newIsAuthorized)",
1999
+ "event SetMaxCollateralPerUser(address indexed collateralToken, uint256 maxCollateralPerUser)",
2000
+ "event SetMaxTakeableAssets(address indexed loanToken, uint256 maxTakeableAssets)",
2001
+ "event SetMaxTotalUnits(address indexed loanToken, uint128 maxTotalUnits)",
2002
+ "event SetObligationTradingFee(bytes32 indexed id_, uint256 indexed index, uint256 newTradingFee)",
1947
2003
  "event SetOwner(address indexed owner)",
1948
2004
  "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)"
2005
+ "event ShuffleSession(address indexed caller, address indexed onBehalf, bytes32 session)",
2006
+ "event Slash(address caller, bytes32 indexed id_, address indexed user, uint256 credit, uint256 latestLossIndex)",
2007
+ "event SupplyCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf)",
2008
+ "event Take(address caller, bytes32 indexed id_, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, address sellerReceiver, bytes32 group, uint256 consumed, uint256 totalUnits)",
2009
+ "event Withdraw(address caller, bytes32 indexed id_, uint256 obligationUnits, address indexed onBehalf, address indexed receiver)",
2010
+ "event WithdrawCollateral(address caller, bytes32 indexed id_, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
1954
2011
  ]);
1955
2012
 
1956
2013
  //#endregion
@@ -2243,8 +2300,8 @@ const chains$1 = {
2243
2300
  name: "base",
2244
2301
  custom: {
2245
2302
  morpho: {
2246
- address: "0x4C752Cdc4b13c9A6a933CbecfE050eC0BA0B45f9",
2247
- blockCreated: 42365274
2303
+ address: "0xee437005ba0a3d0e9bc6510775c41f23ed2909e1",
2304
+ blockCreated: 43515847
2248
2305
  },
2249
2306
  morphoBlue: {
2250
2307
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -2273,8 +2330,8 @@ const chains$1 = {
2273
2330
  name: "ethereum-virtual-testnet",
2274
2331
  custom: {
2275
2332
  morpho: {
2276
- address: "0x9ac49a344376964291f7289663beb78e2952de44",
2277
- blockCreated: 23229385
2333
+ address: "0xc1c6e6fa308eeef18e96be420d8ccb218215a26c",
2334
+ blockCreated: 23244321
2278
2335
  },
2279
2336
  morphoBlue: {
2280
2337
  address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
@@ -2301,9 +2358,13 @@ const chains$1 = {
2301
2358
  ...anvil,
2302
2359
  id: ChainId.ANVIL,
2303
2360
  name: "anvil",
2361
+ contracts: { multicall3: {
2362
+ address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
2363
+ blockCreated: 0
2364
+ } },
2304
2365
  custom: {
2305
2366
  morpho: {
2306
- address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
2367
+ address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
2307
2368
  blockCreated: 0
2308
2369
  },
2309
2370
  morphoBlue: {
@@ -2311,8 +2372,8 @@ const chains$1 = {
2311
2372
  blockCreated: 0
2312
2373
  },
2313
2374
  mempool: {
2314
- address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
2315
- blockCreated: 23223727
2375
+ address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
2376
+ blockCreated: 0
2316
2377
  },
2317
2378
  vaults: { factories: {
2318
2379
  v1_0: {
@@ -2514,6 +2575,7 @@ var Random_exports = /* @__PURE__ */ __exportAll({
2514
2575
  address: () => address,
2515
2576
  bool: () => bool,
2516
2577
  bytes: () => bytes,
2578
+ createRng: () => createRng,
2517
2579
  float: () => float,
2518
2580
  hex: () => hex,
2519
2581
  int: () => int,
@@ -2531,7 +2593,19 @@ const hashSeed = (seed) => {
2531
2593
  }
2532
2594
  return hash >>> 0;
2533
2595
  };
2534
- const createSeededRng = (seed) => {
2596
+ /**
2597
+ * Creates an isolated seeded RNG instance — safe for concurrent use.
2598
+ * @param seed - Seed string used to derive the initial RNG state.
2599
+ */
2600
+ function createRng(seed) {
2601
+ const rng = createSeededRngFn(seed);
2602
+ return {
2603
+ float: () => rng(),
2604
+ int: (maxExclusive, min = 0) => Math.floor(rng() * (maxExclusive - min)) + min,
2605
+ bool: (probability = .5) => rng() < probability
2606
+ };
2607
+ }
2608
+ const createSeededRngFn = (seed) => {
2535
2609
  let state = hashSeed(seed);
2536
2610
  return () => {
2537
2611
  state += 1831565813;
@@ -2545,7 +2619,7 @@ const createSeededRng = (seed) => {
2545
2619
  */
2546
2620
  function withSeed(seed, fn) {
2547
2621
  const previous = currentRng;
2548
- currentRng = createSeededRng(seed);
2622
+ currentRng = createSeededRngFn(seed);
2549
2623
  try {
2550
2624
  return fn();
2551
2625
  } finally {
@@ -2556,7 +2630,7 @@ function withSeed(seed, fn) {
2556
2630
  * Seeds the global RNG for deterministic test runs.
2557
2631
  */
2558
2632
  function seed(seed) {
2559
- currentRng = createSeededRng(seed);
2633
+ currentRng = createSeededRngFn(seed);
2560
2634
  }
2561
2635
  /**
2562
2636
  * Returns a deterministic random float in [0, 1).
@@ -2752,6 +2826,10 @@ const abi$1 = [
2752
2826
  type: "uint256",
2753
2827
  name: "lltv"
2754
2828
  },
2829
+ {
2830
+ type: "uint256",
2831
+ name: "maxLif"
2832
+ },
2755
2833
  {
2756
2834
  type: "address",
2757
2835
  name: "oracle"
@@ -2760,7 +2838,8 @@ const abi$1 = [
2760
2838
  const CollateralSchema = z$1.object({
2761
2839
  asset: z$1.string().transform(transformAddress),
2762
2840
  oracle: z$1.string().transform(transformAddress),
2763
- lltv: LLTVSchema
2841
+ lltv: LLTVSchema,
2842
+ maxLif: z$1.bigint({ coerce: true }).min(0n).optional().default(0n)
2764
2843
  });
2765
2844
  const CollateralsSchema = z$1.array(CollateralSchema).min(1, { message: "At least one collateral is required" }).refine((collaterals) => {
2766
2845
  for (let i = 1; i < collaterals.length; i++) if (collaterals[i - 1].asset.toLowerCase() > collaterals[i].asset.toLowerCase()) return false;
@@ -2778,6 +2857,7 @@ const from$10 = (parameters) => {
2778
2857
  return {
2779
2858
  asset: parameters.asset.toLowerCase(),
2780
2859
  lltv: from$11(parameters.lltv),
2860
+ maxLif: parameters.maxLif ?? 0n,
2781
2861
  oracle: parameters.oracle.toLowerCase()
2782
2862
  };
2783
2863
  };
@@ -2794,7 +2874,8 @@ function random$3() {
2794
2874
  return from$10({
2795
2875
  asset: address(),
2796
2876
  oracle: address(),
2797
- lltv: .965
2877
+ lltv: .965,
2878
+ maxLif: 0n
2798
2879
  });
2799
2880
  }
2800
2881
 
@@ -3055,7 +3136,7 @@ const ObligationSchema = z$1.object({
3055
3136
  loanToken: z$1.string().transform(transformAddress),
3056
3137
  collaterals: CollateralsSchema,
3057
3138
  maturity: MaturitySchema,
3058
- minCollatValue: z$1.bigint({ coerce: true }).min(0n).optional().default(0n)
3139
+ rcfThreshold: z$1.bigint({ coerce: true }).min(0n)
3059
3140
  });
3060
3141
  const abi = [
3061
3142
  {
@@ -3073,7 +3154,7 @@ const abi = [
3073
3154
  },
3074
3155
  {
3075
3156
  type: "uint256",
3076
- name: "minCollatValue"
3157
+ name: "rcfThreshold"
3077
3158
  }
3078
3159
  ];
3079
3160
  const tupleAbi = [{
@@ -3099,6 +3180,7 @@ const tupleAbi = [{
3099
3180
  * }),
3100
3181
  * ],
3101
3182
  * maturity: Maturity.from("end_of_next_quarter"),
3183
+ * rcfThreshold: 0n,
3102
3184
  * });
3103
3185
  * ```
3104
3186
  */
@@ -3112,7 +3194,7 @@ function from$8(parameters) {
3112
3194
  loanToken: parsedObligation.loanToken.toLowerCase(),
3113
3195
  collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
3114
3196
  maturity: parsedObligation.maturity,
3115
- minCollatValue: parsedObligation.minCollatValue
3197
+ rcfThreshold: parsedObligation.rcfThreshold
3116
3198
  };
3117
3199
  } catch (error) {
3118
3200
  throw new InvalidObligationError(error);
@@ -3129,8 +3211,7 @@ function fromSnakeCase$2(input) {
3129
3211
  }
3130
3212
  /**
3131
3213
  * 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`.
3214
+ * The key is computed as keccak256(abi.encode(loanToken, collaterals, maturity, rcfThreshold)).
3134
3215
  * @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}
3135
3216
  * @param parameters - {@link key.Parameters}
3136
3217
  * @returns The obligation key as a 32-byte hex string. {@link key.ReturnType}
@@ -3154,10 +3235,11 @@ function key(parameters) {
3154
3235
  parameters.collaterals.map((c) => ({
3155
3236
  token: c.asset.toLowerCase(),
3156
3237
  lltv: c.lltv,
3238
+ maxLif: c.maxLif ?? 0n,
3157
3239
  oracle: c.oracle.toLowerCase()
3158
3240
  })),
3159
3241
  BigInt(parameters.maturity),
3160
- parameters.minCollatValue ?? 0n
3242
+ parameters.rcfThreshold
3161
3243
  ]));
3162
3244
  }
3163
3245
  /**
@@ -3173,7 +3255,8 @@ function random$2() {
3173
3255
  return from$8({
3174
3256
  loanToken: address(),
3175
3257
  collaterals: [random$3()],
3176
- maturity: from$9("end_of_next_quarter")
3258
+ maturity: from$9("end_of_next_quarter"),
3259
+ rcfThreshold: 0n
3177
3260
  });
3178
3261
  }
3179
3262
  /**
@@ -3187,7 +3270,8 @@ function fromOffer$1(offer) {
3187
3270
  return from$8({
3188
3271
  loanToken: offer.loanToken,
3189
3272
  collaterals: offer.collaterals,
3190
- maturity: offer.maturity
3273
+ maturity: offer.maturity,
3274
+ rcfThreshold: offer.rcfThreshold
3191
3275
  });
3192
3276
  }
3193
3277
  var InvalidObligationError = class extends BaseError {
@@ -3224,27 +3308,27 @@ function creationCode(parameters) {
3224
3308
  collaterals: parameters.obligation.collaterals.map((collateral) => ({
3225
3309
  token: collateral.asset.toLowerCase(),
3226
3310
  lltv: collateral.lltv,
3311
+ maxLif: collateral.maxLif ?? 0n,
3227
3312
  oracle: collateral.oracle.toLowerCase()
3228
3313
  })),
3229
3314
  maturity: BigInt(parameters.obligation.maturity),
3230
- minCollatValue: 0n
3315
+ rcfThreshold: parameters.obligation.rcfThreshold
3231
3316
  }])]);
3232
3317
  }
3233
3318
  /**
3234
3319
  * 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.
3320
+ * `keccak256(0xff ++ morphoV2 ++ chainId ++ keccak256(creationCode))`.
3237
3321
  *
3238
3322
  * @param parameters - {@link toId.Parameters}
3239
- * @returns The obligation id. {@link toId.ReturnType}
3323
+ * @returns The 32-byte obligation id. {@link toId.ReturnType}
3240
3324
  */
3241
3325
  function toId(parameters) {
3242
- return `0x${keccak256(concatHex([
3326
+ return keccak256(concatHex([
3243
3327
  "0xff",
3244
3328
  parameters.morphoV2.toLowerCase(),
3245
3329
  numberToHex(BigInt(parameters.chainId), { size: 32 }),
3246
3330
  keccak256(creationCode(parameters))
3247
- ])).slice(-40)}`;
3331
+ ]));
3248
3332
  }
3249
3333
 
3250
3334
  //#endregion
@@ -3334,7 +3418,6 @@ var Offer_exports = /* @__PURE__ */ __exportAll({
3334
3418
  fromSnakeCase: () => fromSnakeCase$1,
3335
3419
  hash: () => hash,
3336
3420
  liquidateEvent: () => liquidateEvent,
3337
- obligationId: () => obligationId,
3338
3421
  random: () => random$1,
3339
3422
  repayEvent: () => repayEvent,
3340
3423
  serialize: () => serialize,
@@ -3353,11 +3436,10 @@ let Status = /* @__PURE__ */ function(Status) {
3353
3436
  const OfferSchema = () => {
3354
3437
  return z$1.object({
3355
3438
  maker: z$1.string().transform(transformAddress),
3356
- assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
3357
3439
  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),
3359
3440
  tick: z$1.coerce.number().int().min(0).max(990),
3360
3441
  maturity: MaturitySchema,
3442
+ rcfThreshold: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
3361
3443
  expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
3362
3444
  start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
3363
3445
  group: z$1.union([
@@ -3377,7 +3459,8 @@ const OfferSchema = () => {
3377
3459
  address: z$1.string().transform(transformAddress),
3378
3460
  data: z$1.string().transform(transformHex)
3379
3461
  }),
3380
- receiverIfMakerIsSeller: z$1.string().transform(transformAddress)
3462
+ receiverIfMakerIsSeller: z$1.string().transform(transformAddress),
3463
+ exitOnly: z$1.boolean().optional().default(false)
3381
3464
  }).refine((data) => data.start < data.expiry, {
3382
3465
  message: "start must be before expiry",
3383
3466
  path: ["start"]
@@ -3429,11 +3512,10 @@ function toSnakeCase(offer) {
3429
3512
  */
3430
3513
  const serialize = (offer) => ({
3431
3514
  maker: offer.maker,
3432
- assets: offer.assets.toString(),
3433
3515
  obligationUnits: offer.obligationUnits.toString(),
3434
- obligationShares: offer.obligationShares.toString(),
3435
3516
  tick: offer.tick,
3436
3517
  maturity: Number(offer.maturity),
3518
+ rcfThreshold: offer.rcfThreshold.toString(),
3437
3519
  expiry: Number(offer.expiry),
3438
3520
  start: Number(offer.start),
3439
3521
  group: offer.group,
@@ -3443,13 +3525,15 @@ const serialize = (offer) => ({
3443
3525
  collaterals: offer.collaterals.map((c) => ({
3444
3526
  asset: c.asset,
3445
3527
  oracle: c.oracle,
3446
- lltv: c.lltv.toString()
3528
+ lltv: c.lltv.toString(),
3529
+ maxLif: c.maxLif.toString()
3447
3530
  })),
3448
3531
  callback: {
3449
3532
  address: offer.callback.address,
3450
3533
  data: offer.callback.data
3451
3534
  },
3452
3535
  receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
3536
+ exitOnly: offer.exitOnly,
3453
3537
  hash: hash(offer)
3454
3538
  });
3455
3539
  /**
@@ -3486,7 +3570,7 @@ function random$1(config) {
3486
3570
  const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
3487
3571
  const unit = BigInt(10) ** BigInt(loanTokenDecimals);
3488
3572
  const amountBase = BigInt(100 + int(999901));
3489
- const assetsScaled = config?.assets ?? amountBase * unit;
3573
+ const obligationUnitsScaled = config?.obligationUnits ?? amountBase * unit;
3490
3574
  const emptyCallback = {
3491
3575
  address: zeroAddress,
3492
3576
  data: "0x"
@@ -3494,11 +3578,10 @@ function random$1(config) {
3494
3578
  const maker = config?.maker ?? address();
3495
3579
  return from$7({
3496
3580
  maker,
3497
- assets: assetsScaled,
3498
- obligationUnits: config?.obligationUnits ?? 0n,
3499
- obligationShares: config?.obligationShares ?? 0n,
3581
+ obligationUnits: obligationUnitsScaled,
3500
3582
  tick,
3501
3583
  maturity,
3584
+ rcfThreshold: config?.rcfThreshold ?? 0n,
3502
3585
  expiry: config?.expiry ?? maturity - 1,
3503
3586
  start: config?.start ?? maturity - 10,
3504
3587
  group: config?.group ?? hex(32),
@@ -3510,7 +3593,8 @@ function random$1(config) {
3510
3593
  lltv
3511
3594
  })).sort((a, b) => a.asset.localeCompare(b.asset)),
3512
3595
  callback: config?.callback ?? emptyCallback,
3513
- receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker
3596
+ receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker,
3597
+ exitOnly: config?.exitOnly ?? false
3514
3598
  });
3515
3599
  }
3516
3600
  const weightedChoice = (pairs) => {
@@ -3537,124 +3621,150 @@ function hash(offer) {
3537
3621
  return computed;
3538
3622
  }
3539
3623
  /**
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.
3624
+ * ABI layout matching the Solidity `Offer` struct used by `abi.encode(offer)` in the contract.
3625
+ *
3626
+ * This is a **single top-level tuple** Solidity's `abi.encode(struct)` encodes the struct as one
3627
+ * tuple parameter, not as separate parameters per field. Field order and nesting must exactly
3628
+ * mirror `contracts/interfaces/IMidnight.sol`:
3629
+ *
3630
+ * ```
3631
+ * struct Offer {
3632
+ * Obligation obligation; // nested tuple
3633
+ * bool buy;
3634
+ * address maker;
3635
+ * uint256 obligationUnits;
3636
+ * uint256 start;
3637
+ * uint256 expiry;
3638
+ * uint256 tick;
3639
+ * bytes32 group;
3640
+ * bytes32 session;
3641
+ * address callback;
3642
+ * bytes callbackData;
3643
+ * address receiverIfMakerIsSeller;
3644
+ * bool exitOnly;
3645
+ * }
3646
+ * ```
3545
3647
  */
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",
3648
+ const OfferAbi = [{
3649
+ name: "offer",
3650
+ type: "tuple",
3651
+ components: [
3652
+ {
3653
+ name: "obligation",
3654
+ type: "tuple",
3655
+ components: [
3656
+ {
3657
+ name: "loanToken",
3658
+ type: "address"
3659
+ },
3660
+ {
3661
+ name: "collaterals",
3662
+ type: "tuple[]",
3663
+ components: [
3664
+ {
3665
+ name: "token",
3666
+ type: "address"
3667
+ },
3668
+ {
3669
+ name: "lltv",
3670
+ type: "uint256"
3671
+ },
3672
+ {
3673
+ name: "maxLif",
3674
+ type: "uint256"
3675
+ },
3676
+ {
3677
+ name: "oracle",
3678
+ type: "address"
3679
+ }
3680
+ ]
3681
+ },
3682
+ {
3683
+ name: "maturity",
3684
+ type: "uint256"
3685
+ },
3686
+ {
3687
+ name: "rcfThreshold",
3688
+ type: "uint256"
3689
+ }
3690
+ ]
3691
+ },
3692
+ {
3693
+ name: "buy",
3694
+ type: "bool"
3695
+ },
3696
+ {
3697
+ name: "maker",
3629
3698
  type: "address"
3630
- }, {
3631
- name: "data",
3699
+ },
3700
+ {
3701
+ name: "obligationUnits",
3702
+ type: "uint256"
3703
+ },
3704
+ {
3705
+ name: "start",
3706
+ type: "uint256"
3707
+ },
3708
+ {
3709
+ name: "expiry",
3710
+ type: "uint256"
3711
+ },
3712
+ {
3713
+ name: "tick",
3714
+ type: "uint256"
3715
+ },
3716
+ {
3717
+ name: "group",
3718
+ type: "bytes32"
3719
+ },
3720
+ {
3721
+ name: "session",
3722
+ type: "bytes32"
3723
+ },
3724
+ {
3725
+ name: "callback",
3726
+ type: "address"
3727
+ },
3728
+ {
3729
+ name: "callbackData",
3632
3730
  type: "bytes"
3633
- }]
3634
- },
3635
- {
3636
- name: "receiverIfMakerIsSeller",
3637
- type: "address"
3638
- }
3639
- ];
3731
+ },
3732
+ {
3733
+ name: "receiverIfMakerIsSeller",
3734
+ type: "address"
3735
+ },
3736
+ {
3737
+ name: "exitOnly",
3738
+ type: "bool"
3739
+ }
3740
+ ]
3741
+ }];
3640
3742
  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
- ]);
3743
+ return encodeAbiParameters(OfferAbi, [{
3744
+ obligation: {
3745
+ loanToken: offer.loanToken,
3746
+ collaterals: offer.collaterals.map((c) => ({
3747
+ token: c.asset,
3748
+ lltv: c.lltv,
3749
+ maxLif: c.maxLif ?? 0n,
3750
+ oracle: c.oracle
3751
+ })),
3752
+ maturity: BigInt(offer.maturity),
3753
+ rcfThreshold: offer.rcfThreshold
3754
+ },
3755
+ buy: offer.buy,
3756
+ maker: offer.maker,
3757
+ obligationUnits: offer.obligationUnits,
3758
+ start: BigInt(offer.start),
3759
+ expiry: BigInt(offer.expiry),
3760
+ tick: BigInt(offer.tick),
3761
+ group: offer.group,
3762
+ session: offer.session,
3763
+ callback: offer.callback.address,
3764
+ callbackData: offer.callback.data,
3765
+ receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
3766
+ exitOnly: offer.exitOnly
3767
+ }]);
3658
3768
  }
3659
3769
  function decode$1(data) {
3660
3770
  let decoded;
@@ -3663,31 +3773,33 @@ function decode$1(data) {
3663
3773
  } catch (error) {
3664
3774
  throw new InvalidOfferError(error);
3665
3775
  }
3776
+ const s = decoded[0];
3666
3777
  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) => {
3778
+ loanToken: s.obligation.loanToken,
3779
+ collaterals: s.obligation.collaterals.map((c) => {
3680
3780
  return from$10({
3681
- asset: c.asset,
3781
+ asset: c.token,
3682
3782
  oracle: c.oracle,
3683
- lltv: c.lltv
3783
+ lltv: c.lltv,
3784
+ maxLif: c.maxLif
3684
3785
  });
3685
3786
  }),
3787
+ maturity: from$9(Number(s.obligation.maturity)),
3788
+ rcfThreshold: s.obligation.rcfThreshold,
3789
+ buy: s.buy,
3790
+ maker: s.maker,
3791
+ obligationUnits: s.obligationUnits,
3792
+ start: Number(s.start),
3793
+ expiry: Number(s.expiry),
3794
+ tick: Number(s.tick),
3795
+ group: s.group,
3796
+ session: s.session,
3686
3797
  callback: {
3687
- address: decoded[13].address,
3688
- data: decoded[13].data
3798
+ address: s.callback,
3799
+ data: s.callbackData
3689
3800
  },
3690
- receiverIfMakerIsSeller: decoded[14]
3801
+ receiverIfMakerIsSeller: s.receiverIfMakerIsSeller,
3802
+ exitOnly: s.exitOnly
3691
3803
  });
3692
3804
  }
3693
3805
  /**
@@ -3705,9 +3817,9 @@ const takeEvent = {
3705
3817
  },
3706
3818
  {
3707
3819
  name: "id_",
3708
- type: "bytes20",
3820
+ type: "bytes32",
3709
3821
  indexed: true,
3710
- internalType: "bytes20"
3822
+ internalType: "bytes32"
3711
3823
  },
3712
3824
  {
3713
3825
  name: "maker",
@@ -3745,24 +3857,6 @@ const takeEvent = {
3745
3857
  indexed: false,
3746
3858
  internalType: "uint256"
3747
3859
  },
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
3860
  {
3767
3861
  name: "sellerReceiver",
3768
3862
  type: "address",
@@ -3780,19 +3874,31 @@ const takeEvent = {
3780
3874
  type: "uint256",
3781
3875
  indexed: false,
3782
3876
  internalType: "uint256"
3877
+ },
3878
+ {
3879
+ name: "totalUnits",
3880
+ type: "uint256",
3881
+ indexed: false,
3882
+ internalType: "uint256"
3783
3883
  }
3784
3884
  ],
3785
3885
  anonymous: false
3786
3886
  };
3787
3887
  /**
3788
- * ABI for the Consume event emitted by the Obligation contract.
3888
+ * ABI for the SetConsumed event emitted by the Morpho V2 contract.
3789
3889
  */
3790
3890
  const consumedEvent = {
3791
3891
  type: "event",
3792
- name: "Consume",
3892
+ name: "SetConsumed",
3793
3893
  inputs: [
3794
3894
  {
3795
- name: "user",
3895
+ name: "caller",
3896
+ type: "address",
3897
+ indexed: true,
3898
+ internalType: "address"
3899
+ },
3900
+ {
3901
+ name: "onBehalf",
3796
3902
  type: "address",
3797
3903
  indexed: true,
3798
3904
  internalType: "address"
@@ -3827,9 +3933,9 @@ const repayEvent = {
3827
3933
  },
3828
3934
  {
3829
3935
  name: "id_",
3830
- type: "bytes20",
3936
+ type: "bytes32",
3831
3937
  indexed: true,
3832
- internalType: "bytes20"
3938
+ internalType: "bytes32"
3833
3939
  },
3834
3940
  {
3835
3941
  name: "obligationUnits",
@@ -3861,9 +3967,9 @@ const liquidateEvent = {
3861
3967
  },
3862
3968
  {
3863
3969
  name: "id_",
3864
- type: "bytes20",
3970
+ type: "bytes32",
3865
3971
  indexed: true,
3866
- internalType: "bytes20"
3972
+ internalType: "bytes32"
3867
3973
  },
3868
3974
  {
3869
3975
  name: "collateralIndex",
@@ -3894,6 +4000,12 @@ const liquidateEvent = {
3894
4000
  type: "uint256",
3895
4001
  indexed: false,
3896
4002
  internalType: "uint256"
4003
+ },
4004
+ {
4005
+ name: "latestLossIndex",
4006
+ type: "uint256",
4007
+ indexed: false,
4008
+ internalType: "uint256"
3897
4009
  }
3898
4010
  ],
3899
4011
  anonymous: false
@@ -3913,9 +4025,9 @@ const supplyCollateralEvent = {
3913
4025
  },
3914
4026
  {
3915
4027
  name: "id_",
3916
- type: "bytes20",
4028
+ type: "bytes32",
3917
4029
  indexed: true,
3918
- internalType: "bytes20"
4030
+ internalType: "bytes32"
3919
4031
  },
3920
4032
  {
3921
4033
  name: "collateral",
@@ -3953,9 +4065,9 @@ const withdrawCollateralEvent = {
3953
4065
  },
3954
4066
  {
3955
4067
  name: "id_",
3956
- type: "bytes20",
4068
+ type: "bytes32",
3957
4069
  indexed: true,
3958
- internalType: "bytes20"
4070
+ internalType: "bytes32"
3959
4071
  },
3960
4072
  {
3961
4073
  name: "collateral",
@@ -4228,7 +4340,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
4228
4340
  });
4229
4341
  /**
4230
4342
  * Time breakpoints in seconds for piecewise linear fee interpolation.
4231
- * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d.
4343
+ * Matches on-chain constants: 0d, 1d, 7d, 30d, 90d, 180d, 360d.
4232
4344
  */
4233
4345
  const BREAKPOINTS = [
4234
4346
  0n,
@@ -4236,21 +4348,22 @@ const BREAKPOINTS = [
4236
4348
  604800n,
4237
4349
  2592000n,
4238
4350
  7776000n,
4239
- 15552000n
4351
+ 15552000n,
4352
+ 31104000n
4240
4353
  ];
4241
4354
  /** WAD constant (1e18) for fee scaling. */
4242
4355
  const WAD = 10n ** 18n;
4243
4356
  /**
4244
- * Create a TradingFee from an activation flag and 6 fee values.
4357
+ * Create a TradingFee from an activation flag and 7 fee values.
4245
4358
  * @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).
4359
+ * @param fees - Tuple of 7 fee values in WAD (one per breakpoint: 0d, 1d, 7d, 30d, 90d, 180d, 360d).
4247
4360
  * @returns A new TradingFee instance.
4248
4361
  * @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
4249
- * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
4362
+ * @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 7 elements.
4250
4363
  */
4251
4364
  function from$3(activated, fees) {
4252
- if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
4253
- for (let i = 0; i < 6; i++) {
4365
+ if (fees.length !== 7) throw new InvalidFeesLengthError(fees.length);
4366
+ for (let i = 0; i < 7; i++) {
4254
4367
  const fee = fees[i];
4255
4368
  if (fee < 0n || fee > WAD) throw new InvalidFeeError(fee, i);
4256
4369
  }
@@ -4269,7 +4382,9 @@ function from$3(activated, fees) {
4269
4382
  function compute(tradingFee, timeToMaturity) {
4270
4383
  if (!tradingFee._activated) return 0n;
4271
4384
  const time = BigInt(Math.max(0, Math.floor(timeToMaturity)));
4272
- if (time >= BREAKPOINTS[5]) return tradingFee._fees[5];
4385
+ const maxBreakpoint = BREAKPOINTS[BREAKPOINTS.length - 1];
4386
+ const maxFee = tradingFee._fees[tradingFee._fees.length - 1];
4387
+ if (time >= maxBreakpoint) return maxFee;
4273
4388
  const { index, start, end } = getSegment(time);
4274
4389
  const feeLower = tradingFee._fees[index];
4275
4390
  const feeUpper = tradingFee._fees[index + 1];
@@ -4309,7 +4424,7 @@ function deactivate(tradingFee) {
4309
4424
  /**
4310
4425
  * Get the fee values at each breakpoint.
4311
4426
  * @param tradingFee - The TradingFee instance.
4312
- * @returns The tuple of 6 fee values.
4427
+ * @returns The tuple of 7 fee values.
4313
4428
  */
4314
4429
  function getFees(tradingFee) {
4315
4430
  return tradingFee._fees;
@@ -4320,30 +4435,21 @@ function getFees(tradingFee) {
4320
4435
  * @returns Object with index, start, and end of the segment.
4321
4436
  */
4322
4437
  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
- };
4438
+ for (let segmentEndIndex = 1; segmentEndIndex < BREAKPOINTS.length; segmentEndIndex++) {
4439
+ const end = BREAKPOINTS[segmentEndIndex];
4440
+ if (timeToMaturity < end) {
4441
+ const index = segmentEndIndex - 1;
4442
+ return {
4443
+ index,
4444
+ start: BREAKPOINTS[index],
4445
+ end
4446
+ };
4447
+ }
4448
+ }
4343
4449
  return {
4344
- index: 4,
4345
- start: BREAKPOINTS[4],
4346
- end: BREAKPOINTS[5]
4450
+ index: BREAKPOINTS.length - 2,
4451
+ start: BREAKPOINTS[BREAKPOINTS.length - 2],
4452
+ end: BREAKPOINTS[BREAKPOINTS.length - 1]
4347
4453
  };
4348
4454
  }
4349
4455
  /** Error thrown when a fee value is invalid (negative or exceeds WAD). */
@@ -4353,11 +4459,11 @@ var InvalidFeeError = class extends BaseError {
4353
4459
  super(`Invalid fee at index ${index}: ${fee}. Fee must be between 0 and ${WAD} (WAD).`);
4354
4460
  }
4355
4461
  };
4356
- /** Error thrown when fees array doesn't have exactly 6 elements. */
4462
+ /** Error thrown when fees array doesn't have exactly 7 elements. */
4357
4463
  var InvalidFeesLengthError = class extends BaseError {
4358
4464
  name = "TradingFee.InvalidFeesLengthError";
4359
4465
  constructor(length) {
4360
- super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
4466
+ super(`Invalid fees length: ${length}. Expected exactly 7 fee values.`);
4361
4467
  }
4362
4468
  };
4363
4469
 
@@ -4395,6 +4501,9 @@ function from$2(parameters) {
4395
4501
  var Tree_exports = /* @__PURE__ */ __exportAll({
4396
4502
  DecodeError: () => DecodeError,
4397
4503
  EncodeError: () => EncodeError,
4504
+ MAX_COMPRESSED_OFFERS_BYTES: () => MAX_COMPRESSED_OFFERS_BYTES,
4505
+ MAX_DECOMPRESSED_OFFERS_BYTES: () => MAX_DECOMPRESSED_OFFERS_BYTES,
4506
+ MAX_OFFERS_PER_TREE: () => MAX_OFFERS_PER_TREE,
4398
4507
  SignatureDomainError: () => SignatureDomainError,
4399
4508
  TreeError: () => TreeError,
4400
4509
  VERSION: () => VERSION$1,
@@ -4406,7 +4515,16 @@ var Tree_exports = /* @__PURE__ */ __exportAll({
4406
4515
  signatureDomain: () => signatureDomain,
4407
4516
  signatureTypes: () => signatureTypes
4408
4517
  });
4409
- const VERSION$1 = 1;
4518
+ const VERSION$1 = 2;
4519
+ const MAX_COMPRESSED_OFFERS_BYTES = 1e6;
4520
+ const MAX_DECOMPRESSED_OFFERS_BYTES = 4e6;
4521
+ const MAX_OFFERS_PER_TREE = 100;
4522
+ const ROOT_BYTES = 32;
4523
+ const SIGNATURE_BYTES = 65;
4524
+ const MIN_SIGNED_PAYLOAD_BYTES = 1 + ROOT_BYTES + SIGNATURE_BYTES;
4525
+ const INFLATE_INPUT_CHUNK_BYTES = 64 * 1024;
4526
+ const UTF8_ENCODER = new TextEncoder();
4527
+ const UTF8_DECODER = new TextDecoder();
4410
4528
  /**
4411
4529
  * EIP-712 types for signing the tree root (Root(bytes32 root)).
4412
4530
  */
@@ -4423,29 +4541,83 @@ const signatureTypes = {
4423
4541
  type: "bytes32"
4424
4542
  }]
4425
4543
  };
4426
- const normalizeHash = (hash) => hash.toLowerCase();
4544
+ const gzipOffersPayload = (payload, errorFactory) => {
4545
+ const payloadBytes = UTF8_ENCODER.encode(payload);
4546
+ if (payloadBytes.length > MAX_DECOMPRESSED_OFFERS_BYTES) throw errorFactory(`decompressed offers exceed ${MAX_DECOMPRESSED_OFFERS_BYTES} bytes`);
4547
+ try {
4548
+ const compressed = gzip(payloadBytes);
4549
+ if (compressed.length > MAX_COMPRESSED_OFFERS_BYTES) throw errorFactory(`compressed offers exceed ${MAX_COMPRESSED_OFFERS_BYTES} bytes`);
4550
+ return compressed;
4551
+ } catch (error) {
4552
+ if (error instanceof BaseError) throw error;
4553
+ throw errorFactory("compression failed");
4554
+ }
4555
+ };
4556
+ const gunzipOffersPayload = (compressed, errorFactory) => {
4557
+ if (compressed.length === 0) throw errorFactory("decompression failed");
4558
+ if (compressed.length > MAX_COMPRESSED_OFFERS_BYTES) throw errorFactory(`compressed offers exceed ${MAX_COMPRESSED_OFFERS_BYTES} bytes`);
4559
+ let totalLength = 0;
4560
+ const inflate = new Inflate();
4561
+ const defaultOnData = inflate.onData.bind(inflate);
4562
+ inflate.onData = (chunk) => {
4563
+ totalLength += chunk.length;
4564
+ if (totalLength > MAX_DECOMPRESSED_OFFERS_BYTES) throw errorFactory(`decompressed offers exceed ${MAX_DECOMPRESSED_OFFERS_BYTES} bytes`);
4565
+ defaultOnData(chunk);
4566
+ };
4567
+ try {
4568
+ for (let offset = 0; offset < compressed.length; offset += INFLATE_INPUT_CHUNK_BYTES) {
4569
+ const end = Math.min(offset + INFLATE_INPUT_CHUNK_BYTES, compressed.length);
4570
+ inflate.push(compressed.subarray(offset, end), end === compressed.length);
4571
+ }
4572
+ } catch (error) {
4573
+ if (error instanceof BaseError) throw error;
4574
+ throw errorFactory("decompression failed");
4575
+ }
4576
+ if (inflate.err !== 0) throw errorFactory(inflate.msg || "decompression failed");
4577
+ if (!(inflate.result instanceof Uint8Array)) throw errorFactory("decompression failed");
4578
+ return UTF8_DECODER.decode(inflate.result);
4579
+ };
4580
+ const parseRawOffersPayload = (decoded, errorFactory) => {
4581
+ let rawOffers;
4582
+ try {
4583
+ rawOffers = JSON.parse(decoded);
4584
+ } catch {
4585
+ throw errorFactory("JSON parse failed");
4586
+ }
4587
+ if (!Array.isArray(rawOffers)) throw errorFactory("offers payload must be a JSON array");
4588
+ if (rawOffers.length > MAX_OFFERS_PER_TREE) throw errorFactory(`offers payload exceeds ${MAX_OFFERS_PER_TREE} offers`);
4589
+ return rawOffers;
4590
+ };
4591
+ const assertUniqueOfferHashes = (offers, errorFactory) => {
4592
+ const seen = /* @__PURE__ */ new Set();
4593
+ for (const offer of offers) {
4594
+ const hash$1 = hash(offer);
4595
+ if (seen.has(hash$1)) throw errorFactory(`duplicate offer hash ${hash$1}`);
4596
+ seen.add(hash$1);
4597
+ }
4598
+ };
4427
4599
  /**
4428
4600
  * Builds a Merkle tree from a list of offers.
4429
4601
  *
4430
4602
  * 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.
4603
+ * ordered so that the resulting root is stable regardless of the input order.
4433
4604
  *
4434
4605
  * @param offers - Offers to include in the tree.
4435
- * @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
4606
+ * @returns A `SimpleMerkleTree` of offer hashes representing the offers.
4436
4607
  * @throws {TreeError} If tree building fails due to offer inconsistencies.
4437
4608
  */
4438
4609
  const from$1 = (offers) => {
4439
- const leaves = offers.map((offer) => [hash(offer)]);
4440
- const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
4610
+ assertUniqueOfferHashes(offers, (reason) => new TreeError(reason));
4611
+ const leaves = offers.map((offer) => hash(offer));
4612
+ const tree = SimpleMerkleTree.of(leaves);
4441
4613
  const orderedOffers = orderOffers(tree, offers);
4442
4614
  return Object.assign(tree, { offers: orderedOffers });
4443
4615
  };
4444
4616
  const orderOffers = (tree, offers) => {
4445
4617
  const offerByHash = /* @__PURE__ */ new Map();
4446
- for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
4618
+ for (const offer of offers) offerByHash.set(hash(offer), offer);
4447
4619
  const entries = tree.dump().values.map((value) => {
4448
- const hash = normalizeHash(value.value[0]);
4620
+ const hash = value.value;
4449
4621
  const offer = offerByHash.get(hash);
4450
4622
  if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
4451
4623
  return {
@@ -4460,7 +4632,7 @@ const orderOffers = (tree, offers) => {
4460
4632
  * Generates merkle proofs for all offers in a tree.
4461
4633
  *
4462
4634
  * 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.
4635
+ * without requiring the full tree.
4464
4636
  *
4465
4637
  * @param tree - The {@link Tree} to generate proofs for.
4466
4638
  * @returns Array of proofs - {@link Proof}
@@ -4469,7 +4641,7 @@ const proofs = (tree) => {
4469
4641
  return tree.offers.map((offer) => {
4470
4642
  return {
4471
4643
  offer,
4472
- path: tree.getProof([hash(offer)])
4644
+ path: tree.getProof(hash(offer))
4473
4645
  };
4474
4646
  });
4475
4647
  };
@@ -4601,14 +4773,15 @@ const encodeUnsigned = (tree) => {
4601
4773
  };
4602
4774
  const validateTreeForEncoding = (tree) => {
4603
4775
  if (VERSION$1 > 255) throw new EncodeError(`version overflow: ${VERSION$1} exceeds 255`);
4776
+ if (tree.offers.length > MAX_OFFERS_PER_TREE) throw new EncodeError(`offers payload exceeds ${MAX_OFFERS_PER_TREE} offers`);
4604
4777
  const computed = from$1(tree.offers);
4605
4778
  if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
4606
4779
  };
4607
4780
  const encodeUnsignedBytes = (tree) => {
4608
4781
  const offersPayload = tree.offers.map(serialize);
4609
- const compressed = gzip(JSON.stringify(offersPayload));
4782
+ const compressed = gzipOffersPayload(JSON.stringify(offersPayload), (reason) => new EncodeError(reason));
4610
4783
  const rootBytes = hexToBytes(tree.root);
4611
- const encoded = new Uint8Array(1 + compressed.length + 32);
4784
+ const encoded = new Uint8Array(1 + compressed.length + ROOT_BYTES);
4612
4785
  encoded[0] = VERSION$1;
4613
4786
  encoded.set(compressed, 1);
4614
4787
  encoded.set(rootBytes, 1 + compressed.length);
@@ -4621,10 +4794,11 @@ const encodeUnsignedBytes = (tree) => {
4621
4794
  * Returns the tree with separately validated signature and recovered signer address.
4622
4795
  *
4623
4796
  * Validation order:
4624
- * 1. Version check
4797
+ * 1. Version and static size checks
4625
4798
  * 2. Signature verification (fail-fast, before decompression)
4626
- * 3. Decompression (only if signature valid)
4627
- * 4. Root verification (computed from offers vs embedded root)
4799
+ * 3. Streaming decompression with byte cap
4800
+ * 4. JSON array + offer count checks
4801
+ * 5. Root verification (computed from offers vs embedded root)
4628
4802
  *
4629
4803
  * @example
4630
4804
  * ```typescript
@@ -4641,33 +4815,20 @@ const decode = async (encoded, domain) => {
4641
4815
  const errorFactory = (reason) => new DecodeError(reason);
4642
4816
  const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
4643
4817
  const bytes = hexToBytes(encoded);
4644
- if (bytes.length < 98) throw new DecodeError("payload too short");
4818
+ if (bytes.length < MIN_SIGNED_PAYLOAD_BYTES) throw new DecodeError("payload too short");
4645
4819
  const version = bytes[0];
4646
4820
  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");
4821
+ const signature = bytesToHex(bytes.slice(-SIGNATURE_BYTES));
4822
+ const root = bytesToHex(bytes.slice(-(ROOT_BYTES + SIGNATURE_BYTES), -SIGNATURE_BYTES));
4823
+ assertHex(root, ROOT_BYTES, "root");
4824
+ assertHex(signature, SIGNATURE_BYTES, "signature");
4651
4825
  const signer = await verifySignatureAndRecoverAddress({
4652
4826
  root,
4653
4827
  signature,
4654
4828
  domain: normalizedDomain,
4655
4829
  errorFactory
4656
4830
  });
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)));
4831
+ const tree = from$1(parseRawOffersPayload(gunzipOffersPayload(bytes.slice(1, -(ROOT_BYTES + SIGNATURE_BYTES)), errorFactory), errorFactory).map((o) => OfferSchema().parse(o)));
4671
4832
  if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
4672
4833
  return {
4673
4834
  tree,
@@ -4786,11 +4947,10 @@ async function getOffers(apiClient, parameters) {
4786
4947
  return {
4787
4948
  ...fromSnakeCase$1({
4788
4949
  maker: offerData.maker,
4789
- assets: offerData.assets,
4790
4950
  obligation_units: offerData.obligation_units,
4791
- obligation_shares: offerData.obligation_shares,
4792
4951
  tick: offerData.tick,
4793
4952
  maturity: from$9(offerData.obligation.maturity),
4953
+ rcf_threshold: offerData.obligation.rcf_threshold,
4794
4954
  expiry: offerData.expiry,
4795
4955
  start: offerData.start,
4796
4956
  group: offerData.group,
@@ -4800,13 +4960,15 @@ async function getOffers(apiClient, parameters) {
4800
4960
  collaterals: offerData.obligation.collaterals.map((collateral) => ({
4801
4961
  asset: collateral.token,
4802
4962
  oracle: collateral.oracle,
4803
- lltv: collateral.lltv
4963
+ lltv: collateral.lltv,
4964
+ max_lif: collateral.max_lif
4804
4965
  })),
4805
4966
  callback: {
4806
4967
  address: offerData.callback,
4807
4968
  data: offerData.callback_data
4808
4969
  },
4809
- receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller
4970
+ receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller,
4971
+ exit_only: offerData.exit_only ?? false
4810
4972
  }),
4811
4973
  hash: item.offer_hash,
4812
4974
  consumed: BigInt(item.consumed),
@@ -4847,9 +5009,11 @@ async function getObligations(apiClient, parameters) {
4847
5009
  collaterals: item.collaterals.map((collateral) => ({
4848
5010
  asset: collateral.token,
4849
5011
  oracle: collateral.oracle,
4850
- lltv: collateral.lltv
5012
+ lltv: collateral.lltv,
5013
+ max_lif: collateral.max_lif
4851
5014
  })),
4852
- maturity: from$9(item.maturity)
5015
+ maturity: from$9(item.maturity),
5016
+ rcf_threshold: item.rcf_threshold
4853
5017
  });
4854
5018
  const { obligationId: _, ...quote } = from$4({
4855
5019
  obligationId: item.id,
@@ -5337,6 +5501,34 @@ function lazy(pollFn) {
5337
5501
  })();
5338
5502
  }
5339
5503
 
5504
+ //#endregion
5505
+ //#region src/utils/mapWithConcurrency.ts
5506
+ /**
5507
+ * Map values with a bounded number of concurrent async workers.
5508
+ *
5509
+ * Result ordering always matches the input order.
5510
+ * @param parameters - Input values, concurrency limit, and async mapper.
5511
+ * @returns Mapped results in input order.
5512
+ */
5513
+ async function mapWithConcurrency(parameters) {
5514
+ const { values, limit, run } = parameters;
5515
+ if (values.length === 0) return [];
5516
+ const normalizedLimit = Math.max(1, Math.floor(limit));
5517
+ const workerCount = Math.min(normalizedLimit, values.length);
5518
+ const results = new Array(values.length);
5519
+ let nextIndex = 0;
5520
+ const worker = async () => {
5521
+ while (true) {
5522
+ const index = nextIndex;
5523
+ if (index >= values.length) return;
5524
+ nextIndex += 1;
5525
+ results[index] = await run(values[index], index);
5526
+ }
5527
+ };
5528
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
5529
+ return results;
5530
+ }
5531
+
5340
5532
  //#endregion
5341
5533
  //#region src/utils/wait.ts
5342
5534
  async function wait(time) {
@@ -5378,6 +5570,20 @@ function max() {
5378
5570
  return 0x77e772392b600000;
5379
5571
  }
5380
5572
 
5573
+ //#endregion
5574
+ //#region src/utils/trim.ts
5575
+ /**
5576
+ * Keep the last `keep` entries from an array.
5577
+ * @param array - Source array.
5578
+ * @param keep - Number of entries to keep.
5579
+ * @returns Trimmed copy.
5580
+ */
5581
+ const trimTail = (array, keep) => {
5582
+ if (!Number.isInteger(keep) || keep < 0) throw new Error(`trimTail: expected non-negative integer keep, got ${keep}`);
5583
+ if (array.length <= keep) return array.slice();
5584
+ return array.slice(array.length - keep);
5585
+ };
5586
+
5381
5587
  //#endregion
5382
5588
  //#region src/utils/index.ts
5383
5589
  var utils_exports = /* @__PURE__ */ __exportAll({
@@ -5391,18 +5597,20 @@ var utils_exports = /* @__PURE__ */ __exportAll({
5391
5597
  batchMulticall: () => batchMulticall,
5392
5598
  fromSnakeCase: () => fromSnakeCase$3,
5393
5599
  lazy: () => lazy,
5600
+ mapWithConcurrency: () => mapWithConcurrency,
5394
5601
  max: () => max$1,
5395
5602
  min: () => min,
5396
5603
  poll: () => poll,
5397
5604
  retry: () => retry,
5398
5605
  stringifyBigint: () => stringifyBigint,
5399
5606
  toSnakeCase: () => toSnakeCase$1,
5607
+ trimTail: () => trimTail,
5400
5608
  wait: () => wait
5401
5609
  });
5402
5610
 
5403
5611
  //#endregion
5404
5612
  //#region src/database/drizzle/VERSION.ts
5405
- const VERSION = "router_v1.13";
5613
+ const VERSION = "router_v1.15";
5406
5614
 
5407
5615
  //#endregion
5408
5616
  //#region src/database/drizzle/schema.ts
@@ -5422,6 +5630,7 @@ var EnumTableName = /* @__PURE__ */ function(EnumTableName) {
5422
5630
  EnumTableName["VALIDATIONS"] = "validations";
5423
5631
  EnumTableName["COLLECTORS"] = "collectors";
5424
5632
  EnumTableName["CHAINS"] = "chains";
5633
+ EnumTableName["PENDING_LINKS"] = "pending_links";
5425
5634
  EnumTableName["LOTS"] = "lots";
5426
5635
  EnumTableName["LOTS_POSITIONS"] = "lots_positions";
5427
5636
  EnumTableName["OFFSETS"] = "offsets";
@@ -5434,10 +5643,14 @@ const VERSIONED_TABLE_NAMES = TABLE_NAMES.map((table) => `"${VERSION}"."${table}
5434
5643
  const obligations = s.table(EnumTableName.OBLIGATIONS, {
5435
5644
  obligationKey: varchar("obligation_key", { length: 66 }).primaryKey(),
5436
5645
  loanToken: varchar("loan_token", { length: 42 }).notNull(),
5437
- maturity: integer("maturity").notNull()
5646
+ maturity: integer("maturity").notNull(),
5647
+ rcfThreshold: numeric("rcf_threshold", {
5648
+ precision: 78,
5649
+ scale: 0
5650
+ }).notNull()
5438
5651
  });
5439
5652
  const obligationIdKeys = s.table(EnumTableName.OBLIGATION_ID_KEYS, {
5440
- obligationId: varchar("obligation_id", { length: 42 }).primaryKey(),
5653
+ obligationId: varchar("obligation_id", { length: 66 }).primaryKey(),
5441
5654
  obligationKey: varchar("obligation_key", { length: 66 }).notNull().references(() => obligations.obligationKey, { onDelete: "cascade" }),
5442
5655
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5443
5656
  morphoV2: varchar("morpho_v2", { length: 42 }).notNull()
@@ -5459,7 +5672,7 @@ const groups = s.table(EnumTableName.GROUPS, {
5459
5672
  table.group
5460
5673
  ],
5461
5674
  name: "groups_pk"
5462
- }), index("groups_chain_id_maker_group_consumed_idx").on(table.chainId, table.maker, table.group, table.consumed)]);
5675
+ })]);
5463
5676
  const consumedEvents = s.table(EnumTableName.CONSUMED_EVENTS, {
5464
5677
  eventId: varchar("event_id", { length: 128 }).primaryKey(),
5465
5678
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
@@ -5493,16 +5706,13 @@ const obligationCollateralsV2 = s.table(EnumTableName.OBLIGATION_COLLATERALS_V2,
5493
5706
  asset: varchar("asset", { length: 42 }).notNull(),
5494
5707
  oracleAddress: varchar("oracle_address", { length: 42 }).notNull(),
5495
5708
  lltv: bigint("lltv", { mode: "bigint" }).notNull(),
5709
+ maxLif: bigint("max_lif", { mode: "bigint" }).notNull(),
5496
5710
  collateralIndex: integer("collateral_index").notNull(),
5497
5711
  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
- ]);
5712
+ }, (table) => [primaryKey({
5713
+ columns: [table.obligationKey, table.asset],
5714
+ name: "obligation_collaterals_v2_pk"
5715
+ })]);
5506
5716
  const oracles = s.table(EnumTableName.ORACLES, {
5507
5717
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5508
5718
  address: varchar("address", { length: 42 }).notNull(),
@@ -5518,19 +5728,11 @@ const oracles = s.table(EnumTableName.ORACLES, {
5518
5728
  })]);
5519
5729
  const offers = s.table(EnumTableName.OFFERS, {
5520
5730
  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(),
5731
+ obligationId: varchar("obligation_id", { length: 66 }).notNull().references(() => obligationIdKeys.obligationId, { onDelete: "cascade" }),
5526
5732
  obligationUnits: numeric("obligation_units", {
5527
5733
  precision: 78,
5528
5734
  scale: 0
5529
5735
  }).notNull().default("0"),
5530
- obligationShares: numeric("obligation_shares", {
5531
- precision: 78,
5532
- scale: 0
5533
- }).notNull().default("0"),
5534
5736
  tick: integer("tick").notNull(),
5535
5737
  maturity: integer("maturity").notNull(),
5536
5738
  expiry: integer("expiry").notNull(),
@@ -5543,6 +5745,7 @@ const offers = s.table(EnumTableName.OFFERS, {
5543
5745
  callbackAddress: varchar("callback_address", { length: 42 }).notNull(),
5544
5746
  callbackData: text("callback_data").notNull(),
5545
5747
  receiverIfMakerIsSeller: varchar("receiver_if_maker_is_seller", { length: 42 }),
5748
+ exitOnly: boolean("exit_only").notNull().default(false),
5546
5749
  blockNumber: bigint("block_number", { mode: "number" }).notNull(),
5547
5750
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5548
5751
  }, (table) => [
@@ -5563,13 +5766,16 @@ const offers = s.table(EnumTableName.OFFERS, {
5563
5766
  ],
5564
5767
  name: "offers_groups_fk"
5565
5768
  }).onDelete("cascade"),
5566
- index("offers_group_fk_idx").on(table.groupChainId, table.groupMaker, table.group),
5567
5769
  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)
5770
+ index("offers_obligation_side_tick_idx").on(table.obligationId, table.buy, table.tick),
5771
+ index("offers_obligation_active_tick_idx").on(table.obligationId, table.buy, table.expiry, table.maturity, table.start, table.tick),
5772
+ index("offers_group_maker_idx").on(table.groupMaker, table.hash, table.obligationId),
5773
+ 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`"obligation_units" DESC`, table.hash),
5774
+ 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`"obligation_units" DESC`, table.hash)
5569
5775
  ]);
5570
5776
  const offersCallbacks = s.table(EnumTableName.OFFERS_CALLBACKS, {
5571
5777
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5572
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5778
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5573
5779
  callbackId: varchar("callback_id", { length: 66 })
5574
5780
  }, (table) => [foreignKey({
5575
5781
  columns: [table.offerHash, table.obligationId],
@@ -5610,7 +5816,7 @@ const lots = s.table(EnumTableName.LOTS, {
5610
5816
  user: varchar("user", { length: 42 }).notNull(),
5611
5817
  contract: varchar("contract", { length: 66 }).notNull(),
5612
5818
  group: varchar("group", { length: 66 }).notNull(),
5613
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5819
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5614
5820
  lower: numeric("lower", {
5615
5821
  precision: 78,
5616
5822
  scale: 0
@@ -5655,40 +5861,45 @@ const lots = s.table(EnumTableName.LOTS, {
5655
5861
  groups.group
5656
5862
  ],
5657
5863
  name: "lots_groups_fk"
5658
- }).onDelete("cascade")
5864
+ }).onDelete("cascade"),
5865
+ index("lots_position_group_obligation_idx").on(table.chainId, table.user, table.group, table.obligationId)
5659
5866
  ]);
5660
5867
  const offsets = s.table(EnumTableName.OFFSETS, {
5661
5868
  chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
5662
5869
  user: varchar("user", { length: 42 }).notNull(),
5663
5870
  contract: varchar("contract", { length: 66 }).notNull(),
5664
5871
  group: varchar("group", { length: 66 }).notNull(),
5665
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5872
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5666
5873
  value: numeric("value", {
5667
5874
  precision: 78,
5668
5875
  scale: 0
5669
5876
  }).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")]);
5877
+ }, (table) => [
5878
+ primaryKey({
5879
+ columns: [
5880
+ table.chainId,
5881
+ table.user,
5882
+ table.contract,
5883
+ table.group,
5884
+ table.obligationId
5885
+ ],
5886
+ name: "offsets_pk"
5887
+ }),
5888
+ foreignKey({
5889
+ columns: [
5890
+ table.chainId,
5891
+ table.contract,
5892
+ table.user
5893
+ ],
5894
+ foreignColumns: [
5895
+ lotsPositions.chainId,
5896
+ lotsPositions.contract,
5897
+ lotsPositions.user
5898
+ ],
5899
+ name: "offsets_lots_positions_fk"
5900
+ }).onDelete("cascade"),
5901
+ index("offsets_position_obligation_idx").on(table.chainId, table.contract, table.user, table.obligationId)
5902
+ ]);
5692
5903
  const PositionTypes = s.enum("position_type", Object.values(Type));
5693
5904
  const positionTypes = s.table("position_types", {
5694
5905
  id: serial("id").primaryKey(),
@@ -5775,7 +5986,7 @@ const status = s.table("status", {
5775
5986
  });
5776
5987
  const validations = s.table("validations", {
5777
5988
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5778
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
5989
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5779
5990
  statusId: integer("status_id").notNull().references(() => status.id, { onDelete: "no action" }),
5780
5991
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5781
5992
  }, (table) => [primaryKey({
@@ -5803,8 +6014,33 @@ const chains = s.table(EnumTableName.CHAINS, {
5803
6014
  precision: 78,
5804
6015
  scale: 0
5805
6016
  }).default("0").notNull(),
6017
+ checkpoints: text("checkpoints").default("[]").notNull(),
6018
+ tipHash: text("tip_hash"),
6019
+ finalizedBlockNumber: bigint("finalized_block_number", { mode: "number" }),
6020
+ finalizedBlockHash: text("finalized_block_hash"),
5806
6021
  updatedAt: timestamp("updated_at").defaultNow().notNull()
5807
6022
  }, (table) => [uniqueIndex("chains_chain_id_idx").on(table.chainId)]);
6023
+ const pendingLinks = s.table(EnumTableName.PENDING_LINKS, {
6024
+ key: varchar("key", { length: 191 }).primaryKey(),
6025
+ type: text("type").notNull(),
6026
+ status: text("status").notNull(),
6027
+ chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
6028
+ eventId: varchar("event_id", { length: 128 }).notNull(),
6029
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
6030
+ collateralIndex: integer("collateral_index").notNull(),
6031
+ user: varchar("user", { length: 42 }).notNull(),
6032
+ amount: numeric("amount", {
6033
+ precision: 78,
6034
+ scale: 0
6035
+ }).notNull(),
6036
+ blockNumber: bigint("block_number", { mode: "number" }).notNull(),
6037
+ firstSeenBlock: bigint("first_seen_block", { mode: "number" }).notNull(),
6038
+ lastTriedBlock: bigint("last_tried_block", { mode: "number" }),
6039
+ attempts: integer("attempts").notNull().default(0),
6040
+ ignoredReason: text("ignored_reason"),
6041
+ resolvedAt: timestamp("resolved_at"),
6042
+ updatedAt: timestamp("updated_at").defaultNow().notNull()
6043
+ }, (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
6044
  const trees = s.table(EnumTableName.TREES, {
5809
6045
  root: varchar("root", { length: 66 }).primaryKey(),
5810
6046
  rootSignature: varchar("root_signature", { length: 132 }).notNull(),
@@ -5812,7 +6048,7 @@ const trees = s.table(EnumTableName.TREES, {
5812
6048
  });
5813
6049
  const merklePaths = s.table(EnumTableName.MERKLE_PATHS, {
5814
6050
  offerHash: varchar("offer_hash", { length: 66 }).notNull(),
5815
- obligationId: varchar("obligation_id", { length: 42 }).notNull(),
6051
+ obligationId: varchar("obligation_id", { length: 66 }).notNull(),
5816
6052
  treeRoot: varchar("tree_root", { length: 66 }).notNull().references(() => trees.root, { onDelete: "cascade" }),
5817
6053
  proofNodes: text("proof_nodes").notNull(),
5818
6054
  createdAt: timestamp("created_at").defaultNow().notNull()
@@ -5839,7 +6075,7 @@ function compositeKey(g) {
5839
6075
  //#endregion
5840
6076
  //#region src/gatekeeper/Rules.ts
5841
6077
  var Rules_exports = /* @__PURE__ */ __exportAll({
5842
- amountMutualExclusivity: () => amountMutualExclusivity,
6078
+ amountNonZero: () => amountNonZero,
5843
6079
  callback: () => callback,
5844
6080
  collateralToken: () => collateralToken,
5845
6081
  groupConsistency: () => groupConsistency,
@@ -5910,11 +6146,6 @@ const sameMaker = () => batch("mixed_maker", "Validates that all offers in a bat
5910
6146
  return issues;
5911
6147
  });
5912
6148
  /**
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
6149
  * A validation rule that checks if the offer duration (expiry - start) meets a minimum threshold.
5919
6150
  * @param minSeconds - Minimum required duration in seconds.
5920
6151
  * @returns The issue that was found. If the offer is valid, this will be undefined.
@@ -5932,14 +6163,20 @@ const minDuration = ({ minSeconds }) => single("min_duration", `Validates that o
5932
6163
  const maxCollaterals = ({ max }) => single("max_collaterals", `Validates that an offer has at most ${max} collaterals`, (offer) => {
5933
6164
  if (offer.collaterals.length > max) return { message: `Offer has ${offer.collaterals.length} collaterals, exceeding the maximum of ${max}` };
5934
6165
  });
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" };
6166
+ /**
6167
+ * A validation rule that checks if the offer's obligationUnits is non-zero.
6168
+ * The contract requires a positive amount; this rule rejects early.
6169
+ * @returns The issue that was found. If the offer is valid, this will be undefined.
6170
+ */
6171
+ const amountNonZero = () => single("amount_non_zero", "Validates that obligationUnits is non-zero", (offer) => {
6172
+ if (offer.obligationUnits === 0n) return { message: "obligationUnits must be non-zero" };
5937
6173
  });
5938
6174
  /**
5939
6175
  * 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).
6176
+ * All offers sharing the same group must have the same loan token, obligationUnits,
6177
+ * and side (buy/sell). The contract tracks consumed per group and requires these to match.
5941
6178
  */
5942
- const groupConsistency = () => batch("group_consistency", "Validates that all offers in a group have the same loan token, assets amount, and side", (offers) => {
6179
+ const groupConsistency = () => batch("group_consistency", "Validates that all offers in a group have the same loan token, obligation amounts, and side", (offers) => {
5943
6180
  const issues = /* @__PURE__ */ new Map();
5944
6181
  if (offers.length === 0) return issues;
5945
6182
  const groupMap = /* @__PURE__ */ new Map();
@@ -5953,13 +6190,13 @@ const groupConsistency = () => batch("group_consistency", "Validates that all of
5953
6190
  if (indices.length <= 1) continue;
5954
6191
  const reference = offers[indices[0]];
5955
6192
  const refLoanToken = reference.loanToken.toLowerCase();
5956
- const refAssets = reference.assets;
6193
+ const refUnits = reference.obligationUnits;
5957
6194
  const refBuy = reference.buy;
5958
6195
  for (let j = 1; j < indices.length; j++) {
5959
6196
  const idx = indices[j];
5960
6197
  const offer = offers[idx];
5961
6198
  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}` });
6199
+ else if (offer.obligationUnits !== refUnits) issues.set(idx, { message: `All offers in a group must have the same obligationUnits. Expected ${refUnits}, got ${offer.obligationUnits}` });
5963
6200
  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
6201
  }
5965
6202
  }
@@ -6016,7 +6253,7 @@ const morphoRules = (parameters) => {
6016
6253
  }
6017
6254
  const rules = [
6018
6255
  sameMaker(),
6019
- amountMutualExclusivity(),
6256
+ amountNonZero(),
6020
6257
  groupConsistency(),
6021
6258
  ...config?.minDuration != null ? [minDuration({ minSeconds: config.minDuration })] : [],
6022
6259
  maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),