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