@morpho-org/midnight-sdk 0.1.0 → 1.0.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 (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -46
  3. package/lib/cjs/abis.d.ts +1185 -996
  4. package/lib/cjs/abis.js +1445 -1211
  5. package/lib/cjs/api/MidnightApi.d.ts +22 -16
  6. package/lib/cjs/api/MidnightApi.js +22 -16
  7. package/lib/cjs/api/helpers.js +6 -3
  8. package/lib/cjs/api/types.d.ts +35 -9
  9. package/lib/cjs/constants.d.ts +12 -11
  10. package/lib/cjs/constants.js +14 -12
  11. package/lib/cjs/errors.d.ts +74 -1
  12. package/lib/cjs/errors.js +94 -3
  13. package/lib/cjs/fetch/Market.js +0 -1
  14. package/lib/cjs/fetch/index.d.ts +0 -1
  15. package/lib/cjs/fetch/index.js +0 -1
  16. package/lib/cjs/index.d.ts +1 -1
  17. package/lib/cjs/index.js +2 -23
  18. package/lib/cjs/market/Market.d.ts +99 -33
  19. package/lib/cjs/market/Market.js +137 -28
  20. package/lib/cjs/market/MarketUtils.d.ts +61 -41
  21. package/lib/cjs/market/MarketUtils.js +108 -48
  22. package/lib/cjs/market/Position.d.ts +16 -11
  23. package/lib/cjs/market/Position.js +18 -12
  24. package/lib/cjs/market/PositionUtils.d.ts +6 -4
  25. package/lib/cjs/market/PositionUtils.js +9 -6
  26. package/lib/cjs/math/TickLib.d.ts +22 -0
  27. package/lib/cjs/math/TickLib.js +30 -0
  28. package/lib/cjs/math/index.d.ts +0 -1
  29. package/lib/cjs/math/index.js +0 -1
  30. package/lib/cjs/offers/Offer.d.ts +217 -11
  31. package/lib/cjs/offers/Offer.js +215 -7
  32. package/lib/cjs/offers/OfferUtils.d.ts +245 -139
  33. package/lib/cjs/offers/OfferUtils.js +304 -36
  34. package/lib/cjs/queries/GetPosition.d.ts +1 -1
  35. package/lib/cjs/queries/GetPosition.js +1 -1
  36. package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +66 -38
  37. package/lib/cjs/signatures/EcrecoverRatifierUtils.js +147 -79
  38. package/lib/cjs/signatures/Group.d.ts +12 -4
  39. package/lib/cjs/signatures/Group.js +12 -4
  40. package/lib/cjs/signatures/GroupUtils.d.ts +12 -4
  41. package/lib/cjs/signatures/GroupUtils.js +6 -2
  42. package/lib/cjs/signatures/Payload.d.ts +277 -277
  43. package/lib/cjs/signatures/Payload.js +517 -534
  44. package/lib/cjs/signatures/RatifierUtils.d.ts +57 -0
  45. package/lib/cjs/signatures/RatifierUtils.js +94 -0
  46. package/lib/cjs/signatures/SetterRatifierUtils.d.ts +21 -13
  47. package/lib/cjs/signatures/SetterRatifierUtils.js +25 -20
  48. package/lib/cjs/signatures/Tree.d.ts +28 -16
  49. package/lib/cjs/signatures/Tree.js +25 -13
  50. package/lib/cjs/signatures/TreeUtils.d.ts +181 -62
  51. package/lib/cjs/signatures/TreeUtils.js +73 -76
  52. package/lib/cjs/signatures/index.d.ts +1 -0
  53. package/lib/cjs/signatures/index.js +3 -0
  54. package/lib/cjs/signatures/offerStructInternal.d.ts +14 -0
  55. package/lib/cjs/signatures/offerStructInternal.js +72 -0
  56. package/lib/esm/abis.d.ts +1185 -996
  57. package/lib/esm/abis.js +1445 -1211
  58. package/lib/esm/api/MidnightApi.d.ts +22 -16
  59. package/lib/esm/api/MidnightApi.js +23 -17
  60. package/lib/esm/api/helpers.js +6 -3
  61. package/lib/esm/api/types.d.ts +35 -9
  62. package/lib/esm/constants.d.ts +12 -11
  63. package/lib/esm/constants.js +13 -11
  64. package/lib/esm/errors.d.ts +74 -1
  65. package/lib/esm/errors.js +89 -2
  66. package/lib/esm/fetch/Market.js +0 -1
  67. package/lib/esm/fetch/index.d.ts +0 -1
  68. package/lib/esm/fetch/index.js +0 -1
  69. package/lib/esm/index.d.ts +1 -1
  70. package/lib/esm/index.js +1 -1
  71. package/lib/esm/market/Market.d.ts +99 -33
  72. package/lib/esm/market/Market.js +137 -28
  73. package/lib/esm/market/MarketUtils.d.ts +61 -41
  74. package/lib/esm/market/MarketUtils.js +109 -49
  75. package/lib/esm/market/Position.d.ts +16 -11
  76. package/lib/esm/market/Position.js +19 -13
  77. package/lib/esm/market/PositionUtils.d.ts +6 -4
  78. package/lib/esm/market/PositionUtils.js +9 -6
  79. package/lib/esm/math/TickLib.d.ts +22 -0
  80. package/lib/esm/math/TickLib.js +31 -1
  81. package/lib/esm/math/index.d.ts +0 -1
  82. package/lib/esm/math/index.js +0 -1
  83. package/lib/esm/offers/Offer.d.ts +217 -11
  84. package/lib/esm/offers/Offer.js +216 -8
  85. package/lib/esm/offers/OfferUtils.d.ts +245 -139
  86. package/lib/esm/offers/OfferUtils.js +306 -38
  87. package/lib/esm/queries/GetPosition.d.ts +1 -1
  88. package/lib/esm/queries/GetPosition.js +1 -1
  89. package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +66 -38
  90. package/lib/esm/signatures/EcrecoverRatifierUtils.js +149 -81
  91. package/lib/esm/signatures/Group.d.ts +12 -4
  92. package/lib/esm/signatures/Group.js +12 -4
  93. package/lib/esm/signatures/GroupUtils.d.ts +12 -4
  94. package/lib/esm/signatures/GroupUtils.js +6 -2
  95. package/lib/esm/signatures/Payload.d.ts +277 -277
  96. package/lib/esm/signatures/Payload.js +517 -531
  97. package/lib/esm/signatures/RatifierUtils.d.ts +57 -0
  98. package/lib/esm/signatures/RatifierUtils.js +94 -0
  99. package/lib/esm/signatures/SetterRatifierUtils.d.ts +21 -13
  100. package/lib/esm/signatures/SetterRatifierUtils.js +25 -20
  101. package/lib/esm/signatures/Tree.d.ts +28 -16
  102. package/lib/esm/signatures/Tree.js +25 -13
  103. package/lib/esm/signatures/TreeUtils.d.ts +181 -62
  104. package/lib/esm/signatures/TreeUtils.js +75 -78
  105. package/lib/esm/signatures/index.d.ts +1 -0
  106. package/lib/esm/signatures/index.js +1 -0
  107. package/lib/esm/signatures/offerStructInternal.d.ts +14 -0
  108. package/lib/esm/signatures/offerStructInternal.js +67 -0
  109. package/package.json +28 -32
  110. package/src/index.ts +1 -1
  111. package/lib/cjs/fetch/Offer.d.ts +0 -74
  112. package/lib/cjs/fetch/Offer.js +0 -119
  113. package/lib/cjs/math/ConsumableUnitsLib.d.ts +0 -57
  114. package/lib/cjs/math/ConsumableUnitsLib.js +0 -77
  115. package/lib/esm/fetch/Offer.d.ts +0 -74
  116. package/lib/esm/fetch/Offer.js +0 -116
  117. package/lib/esm/math/ConsumableUnitsLib.d.ts +0 -57
  118. package/lib/esm/math/ConsumableUnitsLib.js +0 -74
@@ -1,7 +1,9 @@
1
+ import { assertNonNegative, DivisionByZeroError, MathLib, } from "@morpho-org/morpho-ts";
1
2
  import { encodeAbiParameters, keccak256, zeroAddress, zeroHash } from "viem";
2
- import { DEFAULT_TICK_SPACING, MAX_CONTINUOUS_FEE, MAX_TICK, OFFER_TYPEHASH, } from "../constants.js";
3
+ import { DEFAULT_TICK_SPACING, MAX_CONTINUOUS_FEE, MAX_OFFER_CAP, MAX_TICK, OFFER_TYPEHASH, } from "../constants.js";
3
4
  import { InvalidOfferGroupError, InvalidOfferParameterError, } from "../errors.js";
4
- import { MarketUtils } from "../market/index.js";
5
+ import { Market, MarketParams, MarketUtils } from "../market/index.js";
6
+ import { TakeAmountsLib, TickLib } from "../math/index.js";
5
7
  import { Offer, } from "./Offer.js";
6
8
  const comparableHex = (value) => value.toLowerCase();
7
9
  const offerHashParams = [
@@ -18,8 +20,8 @@ const offerHashParams = [
18
20
  { name: "receiverIfMakerIsSeller", type: "address" },
19
21
  { name: "ratifier", type: "address" },
20
22
  { name: "reduceOnly", type: "bool" },
21
- { name: "maxUnits", type: "uint256" },
22
- { name: "maxAssets", type: "uint256" },
23
+ { name: "maxUnits", type: "uint128" },
24
+ { name: "maxAssets", type: "uint128" },
23
25
  { name: "continuousFeeCap", type: "uint256" },
24
26
  ];
25
27
  /**
@@ -56,12 +58,14 @@ export var OfferUtils;
56
58
  *
57
59
  * const offer = Offer.create({
58
60
  * market: {
61
+ * chainId: 8453,
62
+ * midnight: "0x0000000000000000000000000000000000001000",
59
63
  * loanToken: "0x0000000000000000000000000000000000006000",
60
64
  * collateralParams: [
61
65
  * {
62
66
  * token: "0x0000000000000000000000000000000000007000",
63
67
  * lltv: 770000000000000000n,
64
- * maxLif: 1061007957559681697n,
68
+ * liquidationCursor: 250000000000000000n,
65
69
  * oracle: "0x0000000000000000000000000000000000008000",
66
70
  * },
67
71
  * ],
@@ -120,12 +124,14 @@ export var OfferUtils;
120
124
  *
121
125
  * const offer = Offer.create({
122
126
  * market: {
127
+ * chainId: 8453,
128
+ * midnight: "0x0000000000000000000000000000000000001000",
123
129
  * loanToken: "0x0000000000000000000000000000000000006000",
124
130
  * collateralParams: [
125
131
  * {
126
132
  * token: "0x0000000000000000000000000000000000007000",
127
133
  * lltv: 770000000000000000n,
128
- * maxLif: 1061007957559681697n,
134
+ * liquidationCursor: 250000000000000000n,
129
135
  * oracle: "0x0000000000000000000000000000000000008000",
130
136
  * },
131
137
  * ],
@@ -183,12 +189,14 @@ export var OfferUtils;
183
189
  *
184
190
  * const offer = Offer.create({
185
191
  * market: {
192
+ * chainId: 8453,
193
+ * midnight: "0x0000000000000000000000000000000000001000",
186
194
  * loanToken: "0x0000000000000000000000000000000000006000",
187
195
  * collateralParams: [
188
196
  * {
189
197
  * token: "0x0000000000000000000000000000000000007000",
190
198
  * lltv: 770000000000000000n,
191
- * maxLif: 1061007957559681697n,
199
+ * liquidationCursor: 250000000000000000n,
192
200
  * oracle: "0x0000000000000000000000000000000000008000",
193
201
  * },
194
202
  * ],
@@ -229,12 +237,14 @@ export var OfferUtils;
229
237
  *
230
238
  * const offer = Offer.create({
231
239
  * market: {
240
+ * chainId: 8453,
241
+ * midnight: "0x0000000000000000000000000000000000001000",
232
242
  * loanToken: "0x0000000000000000000000000000000000006000",
233
243
  * collateralParams: [
234
244
  * {
235
245
  * token: "0x0000000000000000000000000000000000007000",
236
246
  * lltv: 770000000000000000n,
237
- * maxLif: 1061007957559681697n,
247
+ * liquidationCursor: 250000000000000000n,
238
248
  * oracle: "0x0000000000000000000000000000000000008000",
239
249
  * },
240
250
  * ],
@@ -312,7 +322,7 @@ export var OfferUtils;
312
322
  * @param params.start - Optional offer start timestamp; defaults to zero.
313
323
  * @param params.expiry - Offer expiry timestamp.
314
324
  * @returns Normalized start and expiry timestamps.
315
- * @throws {InvalidOfferParameterError} when the range is negative or not strictly increasing.
325
+ * @throws {InvalidOfferParameterError} when the range is negative or expiry is before start.
316
326
  * @example
317
327
  * ```ts
318
328
  * import { OfferUtils } from "@morpho-org/midnight-sdk";
@@ -331,11 +341,11 @@ export var OfferUtils;
331
341
  instruction: "Use a non-negative timestamp.",
332
342
  });
333
343
  }
334
- if (expiry < 0n || expiry <= start) {
344
+ if (expiry < 0n || expiry < start) {
335
345
  throw new InvalidOfferParameterError({
336
346
  parameter: "expiry",
337
347
  value: expiry,
338
- instruction: `Use an expiry greater than start "${start}".`,
348
+ instruction: `Use an expiry greater than or equal to start "${start}".`,
339
349
  });
340
350
  }
341
351
  return { start, expiry };
@@ -376,6 +386,20 @@ export var OfferUtils;
376
386
  instruction: "Use a non-negative cap.",
377
387
  });
378
388
  }
389
+ if (maxUnits > MAX_OFFER_CAP) {
390
+ throw new InvalidOfferParameterError({
391
+ parameter: "maxUnits",
392
+ value: maxUnits,
393
+ instruction: `Use a cap less than or equal to "${MAX_OFFER_CAP}".`,
394
+ });
395
+ }
396
+ if (maxAssets > MAX_OFFER_CAP) {
397
+ throw new InvalidOfferParameterError({
398
+ parameter: "maxAssets",
399
+ value: maxAssets,
400
+ instruction: `Use a cap less than or equal to "${MAX_OFFER_CAP}".`,
401
+ });
402
+ }
379
403
  if ((maxAssets === 0n) === (maxUnits === 0n)) {
380
404
  throw new InvalidOfferParameterError({
381
405
  parameter: "maxUnits/maxAssets",
@@ -458,22 +482,16 @@ export var OfferUtils;
458
482
  * instantiating an `Offer`. `Offer.create` uses the same validation and then
459
483
  * constructs the class instance for grouping and trees.
460
484
  *
461
- * @param params.market - Market params or hydrated market this offer trades.
462
485
  * @param params.buy - Whether the maker buys loan assets.
463
486
  * @param params.maker - Maker address.
464
487
  * @param params.tick - Offer tick.
465
- * @param params.group - Optional consumption group id for already-grouped offers.
466
488
  * @param params.tickSpacing - Optional market tick spacing; defaults to `DEFAULT_TICK_SPACING`.
467
489
  * @param params.maxUnits - Optional unit cap; defaults to zero.
468
490
  * @param params.maxAssets - Optional buyer or seller asset cap; defaults to zero.
469
491
  * @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer; defaults to `MAX_CONTINUOUS_FEE`.
470
492
  * @param params.start - Optional offer start timestamp; defaults to zero.
471
493
  * @param params.expiry - Offer expiry timestamp.
472
- * @param params.callback - Optional callback address; defaults to the zero address.
473
- * @param params.callbackData - Optional callback payload; defaults to `0x`.
474
494
  * @param params.receiverIfMakerIsSeller - Optional receiver used when maker is seller.
475
- * @param params.ratifier - Ratifier contract address.
476
- * @param params.reduceOnly - Optional flag restricting the offer to exposure-reducing execution.
477
495
  * @returns Normalized deterministic offer parameters.
478
496
  * @throws {InvalidOfferParameterError} when a deterministic offer parameter cannot satisfy protocol rules.
479
497
  * @example
@@ -481,26 +499,10 @@ export var OfferUtils;
481
499
  * import { OfferUtils } from "@morpho-org/midnight-sdk";
482
500
  *
483
501
  * const params = OfferUtils.validateOfferParams({
484
- * market: {
485
- * loanToken: "0x0000000000000000000000000000000000006000",
486
- * collateralParams: [
487
- * {
488
- * token: "0x0000000000000000000000000000000000007000",
489
- * lltv: 770000000000000000n,
490
- * maxLif: 1061007957559681697n,
491
- * oracle: "0x0000000000000000000000000000000000008000",
492
- * },
493
- * ],
494
- * maturity: 54_000n,
495
- * rcfThreshold: 0n,
496
- * enterGate: "0x0000000000000000000000000000000000000000",
497
- * liquidatorGate: "0x0000000000000000000000000000000000000000",
498
- * },
499
502
  * buy: true,
500
503
  * maker: "0x0000000000000000000000000000000000009000",
501
504
  * tick: 5_000n,
502
505
  * expiry: 3_600n,
503
- * ratifier: "0x0000000000000000000000000000000000004000",
504
506
  * maxUnits: 100n,
505
507
  * });
506
508
  * console.log(params.maxAssets);
@@ -543,12 +545,14 @@ export var OfferUtils;
543
545
  *
544
546
  * const offer = Offer.create({
545
547
  * market: {
548
+ * chainId: 8453,
549
+ * midnight: "0x0000000000000000000000000000000000001000",
546
550
  * loanToken: "0x0000000000000000000000000000000000006000",
547
551
  * collateralParams: [
548
552
  * {
549
553
  * token: "0x0000000000000000000000000000000000007000",
550
554
  * lltv: 770000000000000000n,
551
- * maxLif: 1061007957559681697n,
555
+ * liquidationCursor: 250000000000000000n,
552
556
  * oracle: "0x0000000000000000000000000000000000008000",
553
557
  * },
554
558
  * ],
@@ -577,7 +581,7 @@ export var OfferUtils;
577
581
  const first = offers[0];
578
582
  const expectedMaker = comparableHex(first.maker);
579
583
  const expectedBuy = first.buy;
580
- const expectedLoanToken = comparableHex(first.market.loanToken);
584
+ const expectedLoanToken = comparableHex(MarketParams.from(first.market).loanToken);
581
585
  const expectedMaxUnits = first.maxUnits;
582
586
  const expectedMaxAssets = first.maxAssets;
583
587
  for (const offer of offers) {
@@ -588,11 +592,14 @@ export var OfferUtils;
588
592
  throw new InvalidOfferGroupError("All offers in a group must use the same maker side.");
589
593
  }
590
594
  if (offer.maxUnits < 0n ||
595
+ offer.maxUnits > MAX_OFFER_CAP ||
591
596
  offer.maxAssets < 0n ||
597
+ offer.maxAssets > MAX_OFFER_CAP ||
592
598
  (offer.maxAssets === 0n) === (offer.maxUnits === 0n)) {
593
- throw new InvalidOfferGroupError("Every offer must set exactly one non-zero non-negative cap.");
599
+ throw new InvalidOfferGroupError("Every offer must set exactly one non-zero uint128 cap.");
594
600
  }
595
- if (comparableHex(offer.market.loanToken) !== expectedLoanToken) {
601
+ if (comparableHex(MarketParams.from(offer.market).loanToken) !==
602
+ expectedLoanToken) {
596
603
  throw new InvalidOfferGroupError("All offers in a group must use the same loan token.");
597
604
  }
598
605
  if (offer.maxUnits !== expectedMaxUnits ||
@@ -608,6 +615,265 @@ export var OfferUtils;
608
615
  return [...offers];
609
616
  }
610
617
  OfferUtils.validateOfferGroup = validateOfferGroup;
618
+ /**
619
+ * Converts an offer tick into its WAD zero-coupon price.
620
+ *
621
+ * Use for display or local quote checks when accepting any plain object
622
+ * matching `IOffer` or an `Offer` instance.
623
+ *
624
+ * @param offer - Offer to inspect.
625
+ * @returns WAD price rounded to the protocol price quantum.
626
+ * @throws {NegativeValueError} when `offer.tick` is negative.
627
+ * @throws {TickOutOfRangeError} when `offer.tick` exceeds `MAX_TICK`.
628
+ * @example
629
+ * ```ts
630
+ * import { OfferUtils } from "@morpho-org/midnight-sdk";
631
+ *
632
+ * const price = OfferUtils.getPrice({ tick: 5_000n });
633
+ * console.log(price);
634
+ * ```
635
+ */
636
+ function getPrice(offer) {
637
+ return TickLib.tickToPrice(offer.tick);
638
+ }
639
+ OfferUtils.getPrice = getPrice;
640
+ /**
641
+ * Converts an offer tick into a WAD per-second simple rate at a timestamp.
642
+ *
643
+ * The rate is the offer's fixed period rate divided by the market's remaining
644
+ * time to maturity at `timestamp`, rounded up.
645
+ *
646
+ * @param params.offer - Offer to inspect.
647
+ * @param params.timestamp - Timestamp at which the rate is calculated.
648
+ * @returns WAD per-second simple rate rounded up.
649
+ * @throws {NegativeValueError} when `market.maturity`, `timestamp`, or `tick` is negative.
650
+ * @throws {TickOutOfRangeError} when `tick` exceeds `MAX_TICK`.
651
+ * @throws {DivisionByZeroError} when the tick price is zero or `timestamp` is at or after maturity.
652
+ * @example
653
+ * ```ts
654
+ * import { Offer, OfferUtils } from "@morpho-org/midnight-sdk";
655
+ *
656
+ * const offer = Offer.from({
657
+ * market: {
658
+ * loanToken: "0x0000000000000000000000000000000000006000",
659
+ * collateralParams: [
660
+ * {
661
+ * token: "0x0000000000000000000000000000000000007000",
662
+ * lltv: 770000000000000000n,
663
+ * liquidationCursor: 250000000000000000n,
664
+ * oracle: "0x0000000000000000000000000000000000008000",
665
+ * },
666
+ * ],
667
+ * maturity: 54_000n,
668
+ * rcfThreshold: 0n,
669
+ * enterGate: "0x0000000000000000000000000000000000000000",
670
+ * liquidatorGate: "0x0000000000000000000000000000000000000000",
671
+ * },
672
+ * buy: true,
673
+ * maker: "0x0000000000000000000000000000000000009000",
674
+ * start: 0n,
675
+ * expiry: 3_600n,
676
+ * tick: 5_000n,
677
+ * callback: "0x0000000000000000000000000000000000000000",
678
+ * callbackData: "0x",
679
+ * receiverIfMakerIsSeller: "0x0000000000000000000000000000000000000000",
680
+ * ratifier: "0x0000000000000000000000000000000000004000",
681
+ * reduceOnly: false,
682
+ * maxUnits: 100n,
683
+ * maxAssets: 0n,
684
+ * continuousFeeCap: 317097919n,
685
+ * });
686
+ * const rate = OfferUtils.getRate({ offer, timestamp: 1_000n });
687
+ * console.log(rate);
688
+ * ```
689
+ */
690
+ function getRate(params) {
691
+ const market = MarketParams.from(params.offer.market);
692
+ const timestamp = BigInt(params.timestamp);
693
+ assertNonNegative("market.maturity", market.maturity);
694
+ assertNonNegative("timestamp", timestamp);
695
+ const timeToMaturity = MathLib.zeroFloorSub(market.maturity, timestamp);
696
+ if (timeToMaturity === 0n) {
697
+ throw new DivisionByZeroError("timeToMaturity");
698
+ }
699
+ return MathLib.mulDiv(TickLib.tickToRate(params.offer.tick), 1n, timeToMaturity, "Up");
700
+ }
701
+ OfferUtils.getRate = getRate;
702
+ /**
703
+ * Converts an offer tick into a WAD simple annual percentage rate at a timestamp.
704
+ *
705
+ * It computes time to maturity from the offer market and delegates the final
706
+ * tick annualization to `TickLib.tickToApr`.
707
+ *
708
+ * @param params.offer - Offer to inspect.
709
+ * @param params.timestamp - Timestamp at which the APR is calculated.
710
+ * @returns WAD simple APR rounded up.
711
+ * @throws {NegativeValueError} when `market.maturity`, `timestamp`, or `tick` is negative.
712
+ * @throws {TickOutOfRangeError} when `tick` exceeds `MAX_TICK`.
713
+ * @throws {DivisionByZeroError} when the tick price is zero or `timestamp` is at or after maturity.
714
+ * @example
715
+ * ```ts
716
+ * import { Offer, OfferUtils } from "@morpho-org/midnight-sdk";
717
+ *
718
+ * const offer = Offer.from({
719
+ * market: {
720
+ * loanToken: "0x0000000000000000000000000000000000006000",
721
+ * collateralParams: [
722
+ * {
723
+ * token: "0x0000000000000000000000000000000000007000",
724
+ * lltv: 770000000000000000n,
725
+ * liquidationCursor: 250000000000000000n,
726
+ * oracle: "0x0000000000000000000000000000000000008000",
727
+ * },
728
+ * ],
729
+ * maturity: 54_000n,
730
+ * rcfThreshold: 0n,
731
+ * enterGate: "0x0000000000000000000000000000000000000000",
732
+ * liquidatorGate: "0x0000000000000000000000000000000000000000",
733
+ * },
734
+ * buy: true,
735
+ * maker: "0x0000000000000000000000000000000000009000",
736
+ * start: 0n,
737
+ * expiry: 3_600n,
738
+ * tick: 5_000n,
739
+ * callback: "0x0000000000000000000000000000000000000000",
740
+ * callbackData: "0x",
741
+ * receiverIfMakerIsSeller: "0x0000000000000000000000000000000000000000",
742
+ * ratifier: "0x0000000000000000000000000000000000004000",
743
+ * reduceOnly: false,
744
+ * maxUnits: 100n,
745
+ * maxAssets: 0n,
746
+ * continuousFeeCap: 317097919n,
747
+ * });
748
+ * const apr = OfferUtils.getApr({ offer, timestamp: 1_000n });
749
+ * console.log(apr);
750
+ * ```
751
+ */
752
+ function getApr(params) {
753
+ const market = MarketParams.from(params.offer.market);
754
+ const timestamp = BigInt(params.timestamp);
755
+ assertNonNegative("market.maturity", market.maturity);
756
+ assertNonNegative("timestamp", timestamp);
757
+ return TickLib.tickToApr(params.offer.tick, MathLib.zeroFloorSub(market.maturity, timestamp));
758
+ }
759
+ OfferUtils.getApr = getApr;
760
+ /**
761
+ * Returns remaining units accepted by an offer's cap at a timestamp.
762
+ *
763
+ * The offer must carry a hydrated {@link Market} so the current market
764
+ * continuous fee and settlement-fee buckets are available locally. Fetch the
765
+ * current `consumed(maker, group)` value separately and pass it as input.
766
+ *
767
+ * @param params.offer - Offer to inspect. Its market must be hydrated.
768
+ * @param params.consumed - Amount already consumed from the offer group.
769
+ * @param params.timestamp - Timestamp used to compute market time to maturity.
770
+ * @returns Remaining consumable units accepted by Midnight `take`.
771
+ * @throws {InvalidOfferParameterError} when the offer does not carry hydrated market state or has invalid caps.
772
+ * @throws {NegativeValueError} when `consumed`, `timestamp`, offer limits, or delegated math inputs are negative.
773
+ * @throws {TickOutOfRangeError} when `tick` exceeds `MAX_TICK`.
774
+ * @throws {SettlementFeeExceedsPriceError} when settlement fee exceeds a buy-offer price.
775
+ * @example
776
+ * ```ts
777
+ * import { OfferUtils, midnightAbi } from "@morpho-org/midnight-sdk";
778
+ * import { createPublicClient, http } from "viem";
779
+ * import { base } from "viem/chains";
780
+ * import { readContract } from "viem/actions";
781
+ *
782
+ * const client = createPublicClient({ chain: base, transport: http() });
783
+ * const offer = {
784
+ * market: {
785
+ * params: {
786
+ * chainId: 8453,
787
+ * midnight: "0x0000000000000000000000000000000000001000",
788
+ * loanToken: "0x0000000000000000000000000000000000006000",
789
+ * collateralParams: [
790
+ * {
791
+ * token: "0x0000000000000000000000000000000000007000",
792
+ * lltv: 770000000000000000n,
793
+ * liquidationCursor: 250000000000000000n,
794
+ * oracle: "0x0000000000000000000000000000000000008000",
795
+ * },
796
+ * ],
797
+ * maturity: 54_000n,
798
+ * rcfThreshold: 0n,
799
+ * enterGate: "0x0000000000000000000000000000000000000000",
800
+ * liquidatorGate: "0x0000000000000000000000000000000000000000",
801
+ * },
802
+ * totalUnits: 1_000n,
803
+ * lossFactor: 0n,
804
+ * withdrawable: 500n,
805
+ * continuousFeeCredit: 0n,
806
+ * settlementFeeCbps: [1, 2, 3, 4, 5, 6, 7],
807
+ * continuousFee: 10,
808
+ * tickSpacing: 4,
809
+ * },
810
+ * buy: true,
811
+ * maker: "0x0000000000000000000000000000000000009000",
812
+ * start: 0n,
813
+ * expiry: 3_600n,
814
+ * tick: 5_000n,
815
+ * callback: "0x0000000000000000000000000000000000000000",
816
+ * callbackData: "0x",
817
+ * receiverIfMakerIsSeller: "0x0000000000000000000000000000000000000000",
818
+ * ratifier: "0x0000000000000000000000000000000000004000",
819
+ * reduceOnly: false,
820
+ * maxUnits: 100n,
821
+ * maxAssets: 0n,
822
+ * continuousFeeCap: 317097919n,
823
+ * } as const;
824
+ * const consumed = await readContract(client, {
825
+ * address: "0x0000000000000000000000000000000000001000",
826
+ * abi: midnightAbi,
827
+ * functionName: "consumed",
828
+ * args: [offer.maker, "0x1111111111111111111111111111111111111111111111111111111111111111"],
829
+ * });
830
+ * const units = OfferUtils.getConsumableUnits({ offer, consumed, timestamp: 1_000n });
831
+ * console.log(units);
832
+ * ```
833
+ */
834
+ function getConsumableUnits(params) {
835
+ const offer = params.offer;
836
+ const consumed = BigInt(params.consumed);
837
+ const maxUnits = BigInt(offer.maxUnits);
838
+ const maxAssets = BigInt(offer.maxAssets);
839
+ const continuousFeeCap = BigInt(offer.continuousFeeCap);
840
+ assertNonNegative("consumed", consumed);
841
+ assertNonNegative("offer.maxUnits", maxUnits);
842
+ assertNonNegative("offer.maxAssets", maxAssets);
843
+ assertNonNegative("offer.continuousFeeCap", continuousFeeCap);
844
+ validateOfferCaps({ maxUnits, maxAssets });
845
+ if (!("params" in offer.market)) {
846
+ throw new InvalidOfferParameterError({
847
+ parameter: "market",
848
+ value: offer.market,
849
+ instruction: "Provide a hydrated Market with continuous fee and settlement fee buckets.",
850
+ });
851
+ }
852
+ const market = Market.from(offer.market);
853
+ if (continuousFeeCap < BigInt(market.continuousFee))
854
+ return 0n;
855
+ if (maxUnits > 0n)
856
+ return MathLib.zeroFloorSub(maxUnits, consumed);
857
+ const remainingAssets = MathLib.zeroFloorSub(maxAssets, consumed);
858
+ const settlementFee = market.getSettlementFee(market.timeToMaturity(params.timestamp));
859
+ if (!offer.buy) {
860
+ const { sellerPrice } = TakeAmountsLib.prices({
861
+ offer,
862
+ settlementFee,
863
+ });
864
+ if (sellerPrice === 0n)
865
+ return MathLib.MAX_UINT_256;
866
+ return MathLib.mulDivDown(remainingAssets, MathLib.WAD, sellerPrice);
867
+ }
868
+ const { buyerPrice } = TakeAmountsLib.prices({
869
+ offer,
870
+ settlementFee,
871
+ });
872
+ if (buyerPrice === 0n)
873
+ return MathLib.MAX_UINT_256;
874
+ return ((remainingAssets + 1n) * MathLib.WAD - 1n) / buyerPrice;
875
+ }
876
+ OfferUtils.getConsumableUnits = getConsumableUnits;
611
877
  /**
612
878
  * Returns an offer expiry timestamp.
613
879
  *
@@ -624,12 +890,14 @@ export var OfferUtils;
624
890
  *
625
891
  * const offer = Offer.create({
626
892
  * market: {
893
+ * chainId: 8453,
894
+ * midnight: "0x0000000000000000000000000000000000001000",
627
895
  * loanToken: "0x0000000000000000000000000000000000006000",
628
896
  * collateralParams: [
629
897
  * {
630
898
  * token: "0x0000000000000000000000000000000000007000",
631
899
  * lltv: 770000000000000000n,
632
- * maxLif: 1061007957559681697n,
900
+ * liquidationCursor: 250000000000000000n,
633
901
  * oracle: "0x0000000000000000000000000000000000008000",
634
902
  * },
635
903
  * ],
@@ -52,4 +52,4 @@ export declare const abi: readonly [{
52
52
  readonly type: "function";
53
53
  }];
54
54
  /** @internal Deployless `GetPosition` query bytecode. */
55
- export declare const code = "0x60808060405234601557610362908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c63d8f172c414610025575f80fd5b346101b85760603660031901126101b8576004356001600160a01b03811691908290036101b857602435906044356001600160a01b038116908190036101b85760e0820182811067ffffffffffffffff8211176102e2576040525f825260208201925f845260408301925f8452606081015f8152608082015f815260a08301915f835260c0840196611000604051906100be81836102f6565b36823788526040516349e2903160e11b8152600481018790526024810188905260c0816044818e5afa9081156101c4575f905f925f91885f925f925f91610243575b506001600160801b039081169091529081168852908116865290811684529182168b521685525f5b60808110156101cf5760405163ecdcc72d60e01b8152600481018890526024810189905260448101829052906020826064818f5afa80156101c4575f90610187575b600192506001600160801b038b519116908260051b015201610128565b506020823d82116101bc575b816101a0602093836102f6565b810103126101b8576101b3600192610318565b61016a565b5f80fd5b3d9150610193565b6040513d5f823e3d90fd5b506001600160801b039283899593818094818e816040519c51168c52511660208b0152511660408901525116606087015251166080850152511660a08301525160c082015f905b60808210610224576110c084f35b6020806001926001600160801b03865116815201930191019091610216565b965050505050505060c0813d60c0116102da575b8161026460c093836102f6565b810103126101b857806001600160801b0361027f8193610318565b918161028d60208301610318565b938161029b60408501610318565b93816102a960608301610318565b938d826102c460a06102bd60808801610318565b9601610318565b929a989694929550509497509450509396610100565b3d9150610257565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176102e257604052565b51906001600160801b03821682036101b85756fea264697066735822122047b31034ba6d0d5a88fb953996f2d97fa501664a716d124ff2e42e0782119d9164736f6c63430008230033";
55
+ export declare const code = "0x60808060405234601557610362908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c63d8f172c414610025575f80fd5b346101b85760603660031901126101b8576004356001600160a01b03811691908290036101b857602435906044356001600160a01b038116908190036101b85760e0820182811067ffffffffffffffff8211176102e2576040525f825260208201925f845260408301925f8452606081015f8152608082015f815260a08301915f835260c0840196611000604051906100be81836102f6565b36823788526040516349e2903160e11b8152600481018790526024810188905260c0816044818e5afa9081156101c4575f905f925f91885f925f925f91610243575b506001600160801b039081169091529081168852908116865290811684529182168b521685525f5b60808110156101cf5760405163ecdcc72d60e01b8152600481018890526024810189905260448101829052906020826064818f5afa80156101c4575f90610187575b600192506001600160801b038b519116908260051b015201610128565b506020823d82116101bc575b816101a0602093836102f6565b810103126101b8576101b3600192610318565b61016a565b5f80fd5b3d9150610193565b6040513d5f823e3d90fd5b506001600160801b039283899593818094818e816040519c51168c52511660208b0152511660408901525116606087015251166080850152511660a08301525160c082015f905b60808210610224576110c084f35b6020806001926001600160801b03865116815201930191019091610216565b965050505050505060c0813d60c0116102da575b8161026460c093836102f6565b810103126101b857806001600160801b0361027f8193610318565b918161028d60208301610318565b938161029b60408501610318565b93816102a960608301610318565b938d826102c460a06102bd60808801610318565b9601610318565b929a989694929550509497509450509396610100565b3d9150610257565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176102e257604052565b51906001600160801b03821682036101b85756fea264697066735822122048ab3e1a986178f7e3c65d73416611318a31ef34d18800cb6a1f1ba4dad746b364736f6c63430008230033";
@@ -68,4 +68,4 @@ export const abi = [
68
68
  },
69
69
  ];
70
70
  /** @internal Deployless `GetPosition` query bytecode. */
71
- export const code = "0x60808060405234601557610362908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c63d8f172c414610025575f80fd5b346101b85760603660031901126101b8576004356001600160a01b03811691908290036101b857602435906044356001600160a01b038116908190036101b85760e0820182811067ffffffffffffffff8211176102e2576040525f825260208201925f845260408301925f8452606081015f8152608082015f815260a08301915f835260c0840196611000604051906100be81836102f6565b36823788526040516349e2903160e11b8152600481018790526024810188905260c0816044818e5afa9081156101c4575f905f925f91885f925f925f91610243575b506001600160801b039081169091529081168852908116865290811684529182168b521685525f5b60808110156101cf5760405163ecdcc72d60e01b8152600481018890526024810189905260448101829052906020826064818f5afa80156101c4575f90610187575b600192506001600160801b038b519116908260051b015201610128565b506020823d82116101bc575b816101a0602093836102f6565b810103126101b8576101b3600192610318565b61016a565b5f80fd5b3d9150610193565b6040513d5f823e3d90fd5b506001600160801b039283899593818094818e816040519c51168c52511660208b0152511660408901525116606087015251166080850152511660a08301525160c082015f905b60808210610224576110c084f35b6020806001926001600160801b03865116815201930191019091610216565b965050505050505060c0813d60c0116102da575b8161026460c093836102f6565b810103126101b857806001600160801b0361027f8193610318565b918161028d60208301610318565b938161029b60408501610318565b93816102a960608301610318565b938d826102c460a06102bd60808801610318565b9601610318565b929a989694929550509497509450509396610100565b3d9150610257565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176102e257604052565b51906001600160801b03821682036101b85756fea264697066735822122047b31034ba6d0d5a88fb953996f2d97fa501664a716d124ff2e42e0782119d9164736f6c63430008230033";
71
+ export const code = "0x60808060405234601557610362908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c63d8f172c414610025575f80fd5b346101b85760603660031901126101b8576004356001600160a01b03811691908290036101b857602435906044356001600160a01b038116908190036101b85760e0820182811067ffffffffffffffff8211176102e2576040525f825260208201925f845260408301925f8452606081015f8152608082015f815260a08301915f835260c0840196611000604051906100be81836102f6565b36823788526040516349e2903160e11b8152600481018790526024810188905260c0816044818e5afa9081156101c4575f905f925f91885f925f925f91610243575b506001600160801b039081169091529081168852908116865290811684529182168b521685525f5b60808110156101cf5760405163ecdcc72d60e01b8152600481018890526024810189905260448101829052906020826064818f5afa80156101c4575f90610187575b600192506001600160801b038b519116908260051b015201610128565b506020823d82116101bc575b816101a0602093836102f6565b810103126101b8576101b3600192610318565b61016a565b5f80fd5b3d9150610193565b6040513d5f823e3d90fd5b506001600160801b039283899593818094818e816040519c51168c52511660208b0152511660408901525116606087015251166080850152511660a08301525160c082015f905b60808210610224576110c084f35b6020806001926001600160801b03865116815201930191019091610216565b965050505050505060c0813d60c0116102da575b8161026460c093836102f6565b810103126101b857806001600160801b0361027f8193610318565b918161028d60208301610318565b938161029b60408501610318565b93816102a960608301610318565b938d826102c460a06102bd60808801610318565b9601610318565b929a989694929550509497509450509396610100565b3d9150610257565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176102e257604052565b51906001600160801b03821682036101b85756fea264697066735822122048ab3e1a986178f7e3c65d73416611318a31ef34d18800cb6a1f1ba4dad746b364736f6c63430008230033";