@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.
- 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 +22 -16
- package/lib/cjs/api/helpers.js +6 -3
- 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 +74 -1
- package/lib/cjs/errors.js +94 -3
- package/lib/cjs/fetch/Market.js +0 -1
- package/lib/cjs/fetch/index.d.ts +0 -1
- package/lib/cjs/fetch/index.js +0 -1
- 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 +217 -11
- package/lib/cjs/offers/Offer.js +215 -7
- package/lib/cjs/offers/OfferUtils.d.ts +245 -139
- package/lib/cjs/offers/OfferUtils.js +304 -36
- package/lib/cjs/queries/GetPosition.d.ts +1 -1
- package/lib/cjs/queries/GetPosition.js +1 -1
- package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +66 -38
- package/lib/cjs/signatures/EcrecoverRatifierUtils.js +147 -79
- package/lib/cjs/signatures/Group.d.ts +12 -4
- package/lib/cjs/signatures/Group.js +12 -4
- package/lib/cjs/signatures/GroupUtils.d.ts +12 -4
- package/lib/cjs/signatures/GroupUtils.js +6 -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 +94 -0
- package/lib/cjs/signatures/SetterRatifierUtils.d.ts +21 -13
- package/lib/cjs/signatures/SetterRatifierUtils.js +25 -20
- package/lib/cjs/signatures/Tree.d.ts +28 -16
- package/lib/cjs/signatures/Tree.js +25 -13
- package/lib/cjs/signatures/TreeUtils.d.ts +181 -62
- package/lib/cjs/signatures/TreeUtils.js +73 -76
- package/lib/cjs/signatures/index.d.ts +1 -0
- package/lib/cjs/signatures/index.js +3 -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 +23 -17
- package/lib/esm/api/helpers.js +6 -3
- 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 +74 -1
- package/lib/esm/errors.js +89 -2
- package/lib/esm/fetch/Market.js +0 -1
- package/lib/esm/fetch/index.d.ts +0 -1
- package/lib/esm/fetch/index.js +0 -1
- 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 +217 -11
- package/lib/esm/offers/Offer.js +216 -8
- package/lib/esm/offers/OfferUtils.d.ts +245 -139
- package/lib/esm/offers/OfferUtils.js +306 -38
- package/lib/esm/queries/GetPosition.d.ts +1 -1
- package/lib/esm/queries/GetPosition.js +1 -1
- package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +66 -38
- package/lib/esm/signatures/EcrecoverRatifierUtils.js +149 -81
- package/lib/esm/signatures/Group.d.ts +12 -4
- package/lib/esm/signatures/Group.js +12 -4
- package/lib/esm/signatures/GroupUtils.d.ts +12 -4
- package/lib/esm/signatures/GroupUtils.js +6 -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 +94 -0
- package/lib/esm/signatures/SetterRatifierUtils.d.ts +21 -13
- package/lib/esm/signatures/SetterRatifierUtils.js +25 -20
- package/lib/esm/signatures/Tree.d.ts +28 -16
- package/lib/esm/signatures/Tree.js +25 -13
- package/lib/esm/signatures/TreeUtils.d.ts +181 -62
- package/lib/esm/signatures/TreeUtils.js +75 -78
- package/lib/esm/signatures/index.d.ts +1 -0
- package/lib/esm/signatures/index.js +1 -0
- package/lib/esm/signatures/offerStructInternal.d.ts +14 -0
- package/lib/esm/signatures/offerStructInternal.js +67 -0
- package/package.json +28 -32
- package/src/index.ts +1 -1
- 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
|
@@ -1,61 +1,14 @@
|
|
|
1
1
|
import { deepFreeze } from "@morpho-org/morpho-ts";
|
|
2
|
-
import { concat, keccak256 } from "viem";
|
|
2
|
+
import { concat, keccak256, } from "viem";
|
|
3
3
|
import { MidnightApi } from "../api/MidnightApi.js";
|
|
4
|
-
import { InvalidTreeError, InvalidTreeHeightError } from "../errors.js";
|
|
4
|
+
import { InvalidTreeError, InvalidTreeHeightError, MidnightMempoolValidationError, } from "../errors.js";
|
|
5
5
|
import { Offer, OfferUtils, } from "../offers/index.js";
|
|
6
|
+
import { EcrecoverRatifierUtils, } from "./EcrecoverRatifierUtils.js";
|
|
6
7
|
import { Group } from "./Group.js";
|
|
7
8
|
import { GroupUtils } from "./GroupUtils.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const EMPTY_OFFER_STRUCT = {
|
|
12
|
-
market: {
|
|
13
|
-
loanToken: ZERO_ADDRESS,
|
|
14
|
-
collateralParams: [],
|
|
15
|
-
maturity: 0n,
|
|
16
|
-
rcfThreshold: 0n,
|
|
17
|
-
enterGate: ZERO_ADDRESS,
|
|
18
|
-
liquidatorGate: ZERO_ADDRESS,
|
|
19
|
-
},
|
|
20
|
-
buy: false,
|
|
21
|
-
maker: ZERO_ADDRESS,
|
|
22
|
-
start: 0n,
|
|
23
|
-
expiry: 0n,
|
|
24
|
-
tick: 0n,
|
|
25
|
-
group: ZERO_BYTES32,
|
|
26
|
-
callback: ZERO_ADDRESS,
|
|
27
|
-
callbackData: "0x",
|
|
28
|
-
receiverIfMakerIsSeller: ZERO_ADDRESS,
|
|
29
|
-
ratifier: ZERO_ADDRESS,
|
|
30
|
-
reduceOnly: false,
|
|
31
|
-
maxUnits: 0n,
|
|
32
|
-
maxAssets: 0n,
|
|
33
|
-
continuousFeeCap: 0n,
|
|
34
|
-
};
|
|
35
|
-
const EMPTY_OFFER_DEFAULT_GROUP = OfferUtils.hashStruct(EMPTY_OFFER_STRUCT);
|
|
36
|
-
function isEmptyOfferStruct(offer) {
|
|
37
|
-
return (offer.market.loanToken === ZERO_ADDRESS &&
|
|
38
|
-
offer.market.collateralParams.length === 0 &&
|
|
39
|
-
offer.market.maturity === 0n &&
|
|
40
|
-
offer.market.rcfThreshold === 0n &&
|
|
41
|
-
offer.market.enterGate === ZERO_ADDRESS &&
|
|
42
|
-
offer.market.liquidatorGate === ZERO_ADDRESS &&
|
|
43
|
-
offer.buy === false &&
|
|
44
|
-
offer.maker === ZERO_ADDRESS &&
|
|
45
|
-
offer.start === 0n &&
|
|
46
|
-
offer.expiry === 0n &&
|
|
47
|
-
offer.tick === 0n &&
|
|
48
|
-
(offer.group === ZERO_BYTES32 ||
|
|
49
|
-
offer.group === EMPTY_OFFER_DEFAULT_GROUP) &&
|
|
50
|
-
offer.callback === ZERO_ADDRESS &&
|
|
51
|
-
offer.callbackData === "0x" &&
|
|
52
|
-
offer.receiverIfMakerIsSeller === ZERO_ADDRESS &&
|
|
53
|
-
offer.ratifier === ZERO_ADDRESS &&
|
|
54
|
-
offer.reduceOnly === false &&
|
|
55
|
-
offer.maxUnits === 0n &&
|
|
56
|
-
offer.maxAssets === 0n &&
|
|
57
|
-
offer.continuousFeeCap === 0n);
|
|
58
|
-
}
|
|
9
|
+
import { EMPTY_OFFER_STRUCT, isEmptyOfferStruct, } from "./offerStructInternal.js";
|
|
10
|
+
import { Payload } from "./Payload.js";
|
|
11
|
+
import { SetterRatifierUtils } from "./SetterRatifierUtils.js";
|
|
59
12
|
function isPowerOfTwo(value) {
|
|
60
13
|
return value > 0 && (value & (value - 1)) === 0;
|
|
61
14
|
}
|
|
@@ -74,7 +27,7 @@ function padOfferStructs(offers) {
|
|
|
74
27
|
function assertLeafOffers(offers, leafHashes) {
|
|
75
28
|
const seen = new Set();
|
|
76
29
|
for (const [index, offer] of offers.entries()) {
|
|
77
|
-
if (isEmptyOfferStruct(offer))
|
|
30
|
+
if (isEmptyOfferStruct(offer, { allowDefaultGroup: true }))
|
|
78
31
|
continue;
|
|
79
32
|
const leafHash = leafHashes[index];
|
|
80
33
|
if (seen.has(leafHash)) {
|
|
@@ -106,24 +59,26 @@ export var TreeUtils;
|
|
|
106
59
|
/**
|
|
107
60
|
* Validates a tree against Midnight mempool API policy.
|
|
108
61
|
*
|
|
109
|
-
* This is an API-backed convenience: it encodes each tree leaf
|
|
110
|
-
* `ratifierData`, then sends the temporary payload to the Midnight
|
|
111
|
-
* `POST /mempool/validate` endpoint.
|
|
112
|
-
*
|
|
113
|
-
*
|
|
62
|
+
* This is an API-backed convenience: by default it encodes each tree leaf
|
|
63
|
+
* with empty `ratifierData`, then sends the temporary payload to the Midnight
|
|
64
|
+
* API `POST /mempool/validate` endpoint. Pass `ratification` after signing or
|
|
65
|
+
* Setter root preparation to validate final payload bytes with real
|
|
66
|
+
* `ratifierData`.
|
|
114
67
|
*
|
|
115
68
|
* @param params.chainId - Chain id whose API policy should validate the tree.
|
|
116
|
-
* @param params.tree - Offer tree to validate
|
|
69
|
+
* @param params.tree - Offer tree to validate.
|
|
117
70
|
* @param params.apiUrl - Optional Midnight API URL override used for the validation HTTP request.
|
|
118
71
|
* @param params.timestamp - Optional ISO-8601 timestamp or `Date` selecting the API policy snapshot.
|
|
119
72
|
* @param params.fetch - Optional fetch implementation override used for the API call.
|
|
120
73
|
* @param params.request - Optional fetch options forwarded to the API request.
|
|
121
|
-
* @
|
|
74
|
+
* @param params.ratification - Optional ratification inputs used to validate final payload bytes with real ratifier data.
|
|
75
|
+
* @returns Successful API validation result with `valid: true`.
|
|
122
76
|
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated.
|
|
123
77
|
* @throws {InvalidTreeHeightError} when the resulting height is unsupported.
|
|
124
|
-
* @throws {
|
|
78
|
+
* @throws {PayloadDecodeError} when validation payload encoding fails.
|
|
125
79
|
* @throws {MidnightApiError} when the API returns a non-2xx response.
|
|
126
80
|
* @throws {InvalidMidnightApiResponseError} when the API returns malformed success JSON.
|
|
81
|
+
* @throws {MidnightMempoolValidationError} when the API returns validation issues.
|
|
127
82
|
* @example
|
|
128
83
|
* ```ts
|
|
129
84
|
* import { Offer, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
@@ -131,12 +86,14 @@ export var TreeUtils;
|
|
|
131
86
|
*
|
|
132
87
|
* const offer = Offer.create({
|
|
133
88
|
* market: {
|
|
89
|
+
* chainId: 8453,
|
|
90
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
134
91
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
135
92
|
* collateralParams: [
|
|
136
93
|
* {
|
|
137
94
|
* token: "0x0000000000000000000000000000000000007000",
|
|
138
95
|
* lltv: 770000000000000000n,
|
|
139
|
-
*
|
|
96
|
+
* liquidationCursor: 250000000000000000n,
|
|
140
97
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
141
98
|
* },
|
|
142
99
|
* ],
|
|
@@ -152,20 +109,49 @@ export var TreeUtils;
|
|
|
152
109
|
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
153
110
|
* maxUnits: 100n,
|
|
154
111
|
* });
|
|
155
|
-
*
|
|
112
|
+
* await TreeUtils.mempoolValidate({
|
|
156
113
|
* chainId: 8453,
|
|
157
114
|
* tree: [offer],
|
|
158
115
|
* });
|
|
159
|
-
* console.log(validation.valid);
|
|
160
116
|
* ```
|
|
161
117
|
*/
|
|
162
118
|
async function mempoolValidate(params) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
119
|
+
let items;
|
|
120
|
+
if (params.ratification == null) {
|
|
121
|
+
const offers = "paddedOffers" in params.tree
|
|
122
|
+
? params.tree.offers
|
|
123
|
+
: params.tree.flatMap((entry) => "offers" in entry
|
|
124
|
+
? Group.from(entry).offers
|
|
125
|
+
: [Offer.from(entry)]);
|
|
126
|
+
if (!("paddedOffers" in params.tree)) {
|
|
127
|
+
buildDescriptor(params.tree);
|
|
128
|
+
}
|
|
129
|
+
items = offers.map((offer) => ({
|
|
130
|
+
offer,
|
|
131
|
+
ratifierData: "0x",
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
else if (params.ratification.type === "ecrecover") {
|
|
135
|
+
if (params.ratification.signature != null) {
|
|
136
|
+
items = await EcrecoverRatifierUtils.ratify({
|
|
137
|
+
tree: params.tree,
|
|
138
|
+
signature: params.ratification.signature,
|
|
139
|
+
account: params.ratification.account,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
items = await EcrecoverRatifierUtils.ratify({
|
|
144
|
+
tree: params.tree,
|
|
145
|
+
client: params.ratification.client,
|
|
146
|
+
account: params.ratification.account,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
items = SetterRatifierUtils.ratify({ tree: params.tree });
|
|
152
|
+
}
|
|
153
|
+
const payload = await Payload.encode(items);
|
|
154
|
+
const validation = await MidnightApi.validateMempoolPayload({
|
|
169
155
|
baseUrl: params.apiUrl,
|
|
170
156
|
fetch: params.fetch,
|
|
171
157
|
request: params.request,
|
|
@@ -173,6 +159,10 @@ export var TreeUtils;
|
|
|
173
159
|
timestamp: params.timestamp,
|
|
174
160
|
payload,
|
|
175
161
|
});
|
|
162
|
+
if (!validation.valid) {
|
|
163
|
+
throw new MidnightMempoolValidationError(validation.issues);
|
|
164
|
+
}
|
|
165
|
+
return { valid: true, issues: validation.issues };
|
|
176
166
|
}
|
|
177
167
|
TreeUtils.mempoolValidate = mempoolValidate;
|
|
178
168
|
/**
|
|
@@ -218,12 +208,14 @@ export var TreeUtils;
|
|
|
218
208
|
*
|
|
219
209
|
* const offer = Offer.create({
|
|
220
210
|
* market: {
|
|
211
|
+
* chainId: 8453,
|
|
212
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
221
213
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
222
214
|
* collateralParams: [
|
|
223
215
|
* {
|
|
224
216
|
* token: "0x0000000000000000000000000000000000007000",
|
|
225
217
|
* lltv: 770000000000000000n,
|
|
226
|
-
*
|
|
218
|
+
* liquidationCursor: 250000000000000000n,
|
|
227
219
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
228
220
|
* },
|
|
229
221
|
* ],
|
|
@@ -290,12 +282,14 @@ export var TreeUtils;
|
|
|
290
282
|
*
|
|
291
283
|
* const offer = Offer.create({
|
|
292
284
|
* market: {
|
|
285
|
+
* chainId: 8453,
|
|
286
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
293
287
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
294
288
|
* collateralParams: [
|
|
295
289
|
* {
|
|
296
290
|
* token: "0x0000000000000000000000000000000000007000",
|
|
297
291
|
* lltv: 770000000000000000n,
|
|
298
|
-
*
|
|
292
|
+
* liquidationCursor: 250000000000000000n,
|
|
299
293
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
300
294
|
* },
|
|
301
295
|
* ],
|
|
@@ -326,7 +320,7 @@ export var TreeUtils;
|
|
|
326
320
|
* built-in Ecrecover and Setter helpers call this while generating
|
|
327
321
|
* `ratifierData`.
|
|
328
322
|
*
|
|
329
|
-
* @param params.tree - Tree that
|
|
323
|
+
* @param params.tree - Tree-like data with the root and leaves that contain the leaf.
|
|
330
324
|
* @param params.leafIndex - Leaf index to prove.
|
|
331
325
|
* @returns Proof descriptor.
|
|
332
326
|
* @throws {InvalidTreeError} when leaf index is out of range.
|
|
@@ -337,12 +331,14 @@ export var TreeUtils;
|
|
|
337
331
|
*
|
|
338
332
|
* const offer = Offer.create({
|
|
339
333
|
* market: {
|
|
334
|
+
* chainId: 8453,
|
|
335
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
340
336
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
341
337
|
* collateralParams: [
|
|
342
338
|
* {
|
|
343
339
|
* token: "0x0000000000000000000000000000000000007000",
|
|
344
340
|
* lltv: 770000000000000000n,
|
|
345
|
-
*
|
|
341
|
+
* liquidationCursor: 250000000000000000n,
|
|
346
342
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
347
343
|
* },
|
|
348
344
|
* ],
|
|
@@ -367,8 +363,7 @@ export var TreeUtils;
|
|
|
367
363
|
*/
|
|
368
364
|
function buildProof(params) {
|
|
369
365
|
const leafIndex = BigInt(params.leafIndex);
|
|
370
|
-
if (leafIndex < 0n ||
|
|
371
|
-
leafIndex >= BigInt(params.tree.paddedOffers.length)) {
|
|
366
|
+
if (leafIndex < 0n || leafIndex >= BigInt(params.tree.leaves.length)) {
|
|
372
367
|
throw new InvalidTreeError(`Leaf index "${leafIndex}" is outside the tree.`);
|
|
373
368
|
}
|
|
374
369
|
let index = Number(leafIndex);
|
|
@@ -405,12 +400,14 @@ export var TreeUtils;
|
|
|
405
400
|
*
|
|
406
401
|
* const offer = Offer.create({
|
|
407
402
|
* market: {
|
|
403
|
+
* chainId: 8453,
|
|
404
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
408
405
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
409
406
|
* collateralParams: [
|
|
410
407
|
* {
|
|
411
408
|
* token: "0x0000000000000000000000000000000000007000",
|
|
412
409
|
* lltv: 770000000000000000n,
|
|
413
|
-
*
|
|
410
|
+
* liquidationCursor: 250000000000000000n,
|
|
414
411
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
415
412
|
* },
|
|
416
413
|
* ],
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type OfferStruct } from "../offers/index.js";
|
|
2
|
+
/** @internal Empty protocol offer struct used for Merkle padding. */
|
|
3
|
+
export declare const EMPTY_OFFER_STRUCT: OfferStruct;
|
|
4
|
+
/** @internal Returns whether an address value is the zero address. */
|
|
5
|
+
export declare function isZeroAddress(value: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* @internal Returns whether an offer struct is the protocol empty offer.
|
|
8
|
+
*
|
|
9
|
+
* Tree padding may carry the empty offer's derived default group, while payload
|
|
10
|
+
* decoding only treats the canonical zero-group empty struct as padding.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isEmptyOfferStruct(offer: OfferStruct, options?: {
|
|
13
|
+
readonly allowDefaultGroup?: boolean;
|
|
14
|
+
}): boolean;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { zeroAddress, zeroHash } from "viem";
|
|
2
|
+
import { OfferUtils } from "../offers/index.js";
|
|
3
|
+
/** @internal Empty protocol offer struct used for Merkle padding. */
|
|
4
|
+
export const EMPTY_OFFER_STRUCT = {
|
|
5
|
+
market: {
|
|
6
|
+
chainId: 0n,
|
|
7
|
+
midnight: zeroAddress,
|
|
8
|
+
loanToken: zeroAddress,
|
|
9
|
+
collateralParams: [],
|
|
10
|
+
maturity: 0n,
|
|
11
|
+
rcfThreshold: 0n,
|
|
12
|
+
enterGate: zeroAddress,
|
|
13
|
+
liquidatorGate: zeroAddress,
|
|
14
|
+
},
|
|
15
|
+
buy: false,
|
|
16
|
+
maker: zeroAddress,
|
|
17
|
+
start: 0n,
|
|
18
|
+
expiry: 0n,
|
|
19
|
+
tick: 0n,
|
|
20
|
+
group: zeroHash,
|
|
21
|
+
callback: zeroAddress,
|
|
22
|
+
callbackData: "0x",
|
|
23
|
+
receiverIfMakerIsSeller: zeroAddress,
|
|
24
|
+
ratifier: zeroAddress,
|
|
25
|
+
reduceOnly: false,
|
|
26
|
+
maxUnits: 0n,
|
|
27
|
+
maxAssets: 0n,
|
|
28
|
+
continuousFeeCap: 0n,
|
|
29
|
+
};
|
|
30
|
+
const EMPTY_OFFER_DEFAULT_GROUP = OfferUtils.hashStruct(EMPTY_OFFER_STRUCT);
|
|
31
|
+
/** @internal Returns whether an address value is the zero address. */
|
|
32
|
+
export function isZeroAddress(value) {
|
|
33
|
+
return value.toLowerCase() === zeroAddress;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* @internal Returns whether an offer struct is the protocol empty offer.
|
|
37
|
+
*
|
|
38
|
+
* Tree padding may carry the empty offer's derived default group, while payload
|
|
39
|
+
* decoding only treats the canonical zero-group empty struct as padding.
|
|
40
|
+
*/
|
|
41
|
+
export function isEmptyOfferStruct(offer, options = {}) {
|
|
42
|
+
const hasEmptyGroup = offer.group === zeroHash ||
|
|
43
|
+
(options.allowDefaultGroup === true &&
|
|
44
|
+
offer.group === EMPTY_OFFER_DEFAULT_GROUP);
|
|
45
|
+
return (offer.market.chainId === 0n &&
|
|
46
|
+
isZeroAddress(offer.market.midnight) &&
|
|
47
|
+
isZeroAddress(offer.market.loanToken) &&
|
|
48
|
+
offer.market.collateralParams.length === 0 &&
|
|
49
|
+
offer.market.maturity === 0n &&
|
|
50
|
+
offer.market.rcfThreshold === 0n &&
|
|
51
|
+
isZeroAddress(offer.market.enterGate) &&
|
|
52
|
+
isZeroAddress(offer.market.liquidatorGate) &&
|
|
53
|
+
offer.buy === false &&
|
|
54
|
+
isZeroAddress(offer.maker) &&
|
|
55
|
+
offer.start === 0n &&
|
|
56
|
+
offer.expiry === 0n &&
|
|
57
|
+
offer.tick === 0n &&
|
|
58
|
+
hasEmptyGroup &&
|
|
59
|
+
isZeroAddress(offer.callback) &&
|
|
60
|
+
offer.callbackData === "0x" &&
|
|
61
|
+
isZeroAddress(offer.receiverIfMakerIsSeller) &&
|
|
62
|
+
isZeroAddress(offer.ratifier) &&
|
|
63
|
+
offer.reduceOnly === false &&
|
|
64
|
+
offer.maxUnits === 0n &&
|
|
65
|
+
offer.maxAssets === 0n &&
|
|
66
|
+
offer.continuousFeeCap === 0n);
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morpho-org/midnight-sdk",
|
|
3
3
|
"description": "Viem-based package for Morpho Midnight that exports protocol utilities, fetch helpers, and Midnight API utilities under a dedicated API subpath.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"author": "Morpho Association <contact@morpho.org>",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Rubilmax <rmilon@gmail.com>"
|
|
8
8
|
],
|
|
9
|
-
"repository":
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "github:morpho-org/sdks"
|
|
12
|
+
},
|
|
10
13
|
"homepage": "https://github.com/morpho-org/sdks",
|
|
11
14
|
"bugs": {
|
|
12
15
|
"url": "https://github.com/morpho-org/sdks/issues",
|
|
@@ -16,8 +19,16 @@
|
|
|
16
19
|
"type": "module",
|
|
17
20
|
"main": "src/index.ts",
|
|
18
21
|
"exports": {
|
|
19
|
-
".":
|
|
20
|
-
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./lib/esm/index.d.ts",
|
|
24
|
+
"import": "./lib/esm/index.js",
|
|
25
|
+
"require": "./lib/cjs/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./api": {
|
|
28
|
+
"types": "./lib/esm/api/index.d.ts",
|
|
29
|
+
"import": "./lib/esm/api/index.js",
|
|
30
|
+
"require": "./lib/cjs/api/index.js"
|
|
31
|
+
},
|
|
21
32
|
"./package.json": "./package.json"
|
|
22
33
|
},
|
|
23
34
|
"typesVersions": {
|
|
@@ -31,39 +42,24 @@
|
|
|
31
42
|
"files": [
|
|
32
43
|
"lib"
|
|
33
44
|
],
|
|
34
|
-
"scripts": {
|
|
35
|
-
"prepublish": "$npm_execpath build",
|
|
36
|
-
"compile": "node ../../scripts/compile-solidity.js midnight-sdk",
|
|
37
|
-
"build": "tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
|
|
38
|
-
"build:cjs": "tsc --build tsconfig.build.cjs.json && echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json",
|
|
39
|
-
"build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
|
|
40
|
-
"test": "vitest --root ../.. --project midnight-sdk"
|
|
41
|
-
},
|
|
42
45
|
"peerDependencies": {
|
|
43
46
|
"@morpho-org/morpho-ts": "^2.7.0",
|
|
44
47
|
"viem": "^2.0.0"
|
|
45
48
|
},
|
|
46
49
|
"devDependencies": {
|
|
47
|
-
"
|
|
48
|
-
"@morpho-org/test": "workspace:^",
|
|
49
|
-
"fast-check": "^4.4.0",
|
|
50
|
+
"fast-check": "^4.8.0",
|
|
50
51
|
"typescript": "^6.0.3",
|
|
51
|
-
"viem": "2.
|
|
52
|
-
"vitest": "^4.1.
|
|
52
|
+
"viem": "^2.54.2",
|
|
53
|
+
"vitest": "^4.1.9",
|
|
54
|
+
"@morpho-org/morpho-ts": "^2.7.0",
|
|
55
|
+
"@morpho-org/test": "^2.8.1"
|
|
53
56
|
},
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"./api": {
|
|
62
|
-
"types": "./lib/esm/api/index.d.ts",
|
|
63
|
-
"import": "./lib/esm/api/index.js",
|
|
64
|
-
"require": "./lib/cjs/api/index.js"
|
|
65
|
-
},
|
|
66
|
-
"./package.json": "./package.json"
|
|
67
|
-
}
|
|
57
|
+
"scripts": {
|
|
58
|
+
"prepublish": "$npm_execpath build",
|
|
59
|
+
"compile": "node ../../scripts/compile-solidity.js midnight-sdk",
|
|
60
|
+
"build": "tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
|
|
61
|
+
"build:cjs": "tsc --build tsconfig.build.cjs.json && echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json",
|
|
62
|
+
"build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
|
|
63
|
+
"test": "vitest --root ../.. --project midnight-sdk"
|
|
68
64
|
}
|
|
69
|
-
}
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
package/lib/cjs/fetch/Offer.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { type BigIntish } from "@morpho-org/morpho-ts";
|
|
2
|
-
import type { Address, Client, Hash } from "viem";
|
|
3
|
-
import type { MidnightFetchParams } from "./types.js";
|
|
4
|
-
/**
|
|
5
|
-
* Fetches and computes remaining consumable units for an offer.
|
|
6
|
-
*
|
|
7
|
-
* Unit-capped offers skip settlement-fee lookup, matching the Solidity
|
|
8
|
-
* library's early return. For asset-capped offers, pass the time to maturity
|
|
9
|
-
* for the same block context as the quote.
|
|
10
|
-
*
|
|
11
|
-
* Reads `eth_chainId` only when the viem client has no configured chain id,
|
|
12
|
-
* then reads `Midnight.consumed(offer.maker, group)` and
|
|
13
|
-
* `Midnight.continuousFee(marketId)`. If the offer's continuous fee cap is
|
|
14
|
-
* below the market's current continuous fee, returns zero. For asset-capped
|
|
15
|
-
* offers where `offer.maxUnits` is zero, also reads
|
|
16
|
-
* `Midnight.settlementFee(marketId, timeToMaturity)`.
|
|
17
|
-
*
|
|
18
|
-
* @param client - Viem client used for the reads.
|
|
19
|
-
* @param params.marketId - Market id used for settlement-fee lookup on asset-capped offers.
|
|
20
|
-
* @param params.offer.buy - Whether the maker buys loan assets.
|
|
21
|
-
* @param params.offer.maker - Maker address whose consumed group amount is read.
|
|
22
|
-
* @param params.offer.tick - Offer tick used for asset-to-unit conversion.
|
|
23
|
-
* @param params.offer.maxUnits - Unit cap; when non-zero, settlement-fee lookup is skipped.
|
|
24
|
-
* @param params.offer.maxAssets - Asset cap used when `params.offer.maxUnits` is zero.
|
|
25
|
-
* @param params.offer.continuousFeeCap - Maximum market continuous fee accepted by this offer.
|
|
26
|
-
* @param params.group - Offer group id whose consumed amount is read.
|
|
27
|
-
* @param params.timeToMaturity - Time to maturity used for settlement-fee lookup on asset-capped offers.
|
|
28
|
-
* @param params.account - Optional account used as the `from` field for the reads.
|
|
29
|
-
* @param params.blockNumber - Optional block number used for the reads.
|
|
30
|
-
* @param params.blockTag - Optional block tag used for the reads.
|
|
31
|
-
* @param params.stateOverride - Optional state override set used for the reads.
|
|
32
|
-
* @returns Consumable units.
|
|
33
|
-
* @throws {UnsupportedChainIdError} when no address registry exists for the client chain id.
|
|
34
|
-
* @throws {UnknownAddressError} when the registry has no Midnight address for the client chain id.
|
|
35
|
-
* @throws {NegativeValueError} when asset-capped `timeToMaturity`, offer caps, or SDK math inputs are negative.
|
|
36
|
-
* @throws {InvalidOfferParameterError} when offer caps are both zero or both non-zero.
|
|
37
|
-
* @throws {DivisionByZeroError} when the delegated units conversion divides by zero.
|
|
38
|
-
* @throws {SettlementFeeExceedsPriceError} when settlement fee exceeds a buy offer price.
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* import { fetchConsumableUnits } from "@morpho-org/midnight-sdk";
|
|
42
|
-
* import { createPublicClient, http, zeroHash } from "viem";
|
|
43
|
-
* import { base } from "viem/chains";
|
|
44
|
-
*
|
|
45
|
-
* const client = createPublicClient({ chain: base, transport: http() });
|
|
46
|
-
* const units = await fetchConsumableUnits(client, {
|
|
47
|
-
* marketId: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
48
|
-
* offer: {
|
|
49
|
-
* buy: true,
|
|
50
|
-
* maker: "0x0000000000000000000000000000000000009000",
|
|
51
|
-
* tick: 5_000n,
|
|
52
|
-
* maxUnits: 100n,
|
|
53
|
-
* maxAssets: 0n,
|
|
54
|
-
* continuousFeeCap: 317097919n,
|
|
55
|
-
* },
|
|
56
|
-
* group: zeroHash,
|
|
57
|
-
* timeToMaturity: 3_600n,
|
|
58
|
-
* });
|
|
59
|
-
* console.log(units);
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
export declare function fetchConsumableUnits(client: Client, params: MidnightFetchParams & {
|
|
63
|
-
readonly marketId: Hash;
|
|
64
|
-
readonly offer: {
|
|
65
|
-
readonly buy: boolean;
|
|
66
|
-
readonly maker: Address;
|
|
67
|
-
readonly tick: BigIntish;
|
|
68
|
-
readonly maxUnits: BigIntish;
|
|
69
|
-
readonly maxAssets: BigIntish;
|
|
70
|
-
readonly continuousFeeCap: BigIntish;
|
|
71
|
-
};
|
|
72
|
-
readonly group: Hash;
|
|
73
|
-
readonly timeToMaturity: BigIntish;
|
|
74
|
-
}): Promise<bigint>;
|
package/lib/cjs/fetch/Offer.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fetchConsumableUnits = fetchConsumableUnits;
|
|
4
|
-
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
5
|
-
const actions_1 = require("viem/actions");
|
|
6
|
-
const abis_js_1 = require("../abis.js");
|
|
7
|
-
const index_js_1 = require("../math/index.js");
|
|
8
|
-
const index_js_2 = require("../offers/index.js");
|
|
9
|
-
const utils_js_1 = require("./utils.js");
|
|
10
|
-
/**
|
|
11
|
-
* Fetches and computes remaining consumable units for an offer.
|
|
12
|
-
*
|
|
13
|
-
* Unit-capped offers skip settlement-fee lookup, matching the Solidity
|
|
14
|
-
* library's early return. For asset-capped offers, pass the time to maturity
|
|
15
|
-
* for the same block context as the quote.
|
|
16
|
-
*
|
|
17
|
-
* Reads `eth_chainId` only when the viem client has no configured chain id,
|
|
18
|
-
* then reads `Midnight.consumed(offer.maker, group)` and
|
|
19
|
-
* `Midnight.continuousFee(marketId)`. If the offer's continuous fee cap is
|
|
20
|
-
* below the market's current continuous fee, returns zero. For asset-capped
|
|
21
|
-
* offers where `offer.maxUnits` is zero, also reads
|
|
22
|
-
* `Midnight.settlementFee(marketId, timeToMaturity)`.
|
|
23
|
-
*
|
|
24
|
-
* @param client - Viem client used for the reads.
|
|
25
|
-
* @param params.marketId - Market id used for settlement-fee lookup on asset-capped offers.
|
|
26
|
-
* @param params.offer.buy - Whether the maker buys loan assets.
|
|
27
|
-
* @param params.offer.maker - Maker address whose consumed group amount is read.
|
|
28
|
-
* @param params.offer.tick - Offer tick used for asset-to-unit conversion.
|
|
29
|
-
* @param params.offer.maxUnits - Unit cap; when non-zero, settlement-fee lookup is skipped.
|
|
30
|
-
* @param params.offer.maxAssets - Asset cap used when `params.offer.maxUnits` is zero.
|
|
31
|
-
* @param params.offer.continuousFeeCap - Maximum market continuous fee accepted by this offer.
|
|
32
|
-
* @param params.group - Offer group id whose consumed amount is read.
|
|
33
|
-
* @param params.timeToMaturity - Time to maturity used for settlement-fee lookup on asset-capped offers.
|
|
34
|
-
* @param params.account - Optional account used as the `from` field for the reads.
|
|
35
|
-
* @param params.blockNumber - Optional block number used for the reads.
|
|
36
|
-
* @param params.blockTag - Optional block tag used for the reads.
|
|
37
|
-
* @param params.stateOverride - Optional state override set used for the reads.
|
|
38
|
-
* @returns Consumable units.
|
|
39
|
-
* @throws {UnsupportedChainIdError} when no address registry exists for the client chain id.
|
|
40
|
-
* @throws {UnknownAddressError} when the registry has no Midnight address for the client chain id.
|
|
41
|
-
* @throws {NegativeValueError} when asset-capped `timeToMaturity`, offer caps, or SDK math inputs are negative.
|
|
42
|
-
* @throws {InvalidOfferParameterError} when offer caps are both zero or both non-zero.
|
|
43
|
-
* @throws {DivisionByZeroError} when the delegated units conversion divides by zero.
|
|
44
|
-
* @throws {SettlementFeeExceedsPriceError} when settlement fee exceeds a buy offer price.
|
|
45
|
-
* @example
|
|
46
|
-
* ```ts
|
|
47
|
-
* import { fetchConsumableUnits } from "@morpho-org/midnight-sdk";
|
|
48
|
-
* import { createPublicClient, http, zeroHash } from "viem";
|
|
49
|
-
* import { base } from "viem/chains";
|
|
50
|
-
*
|
|
51
|
-
* const client = createPublicClient({ chain: base, transport: http() });
|
|
52
|
-
* const units = await fetchConsumableUnits(client, {
|
|
53
|
-
* marketId: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
54
|
-
* offer: {
|
|
55
|
-
* buy: true,
|
|
56
|
-
* maker: "0x0000000000000000000000000000000000009000",
|
|
57
|
-
* tick: 5_000n,
|
|
58
|
-
* maxUnits: 100n,
|
|
59
|
-
* maxAssets: 0n,
|
|
60
|
-
* continuousFeeCap: 317097919n,
|
|
61
|
-
* },
|
|
62
|
-
* group: zeroHash,
|
|
63
|
-
* timeToMaturity: 3_600n,
|
|
64
|
-
* });
|
|
65
|
-
* console.log(units);
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
async function fetchConsumableUnits(client, params) {
|
|
69
|
-
const maxUnits = BigInt(params.offer.maxUnits);
|
|
70
|
-
const maxAssets = BigInt(params.offer.maxAssets);
|
|
71
|
-
const continuousFeeCap = BigInt(params.offer.continuousFeeCap);
|
|
72
|
-
(0, morpho_ts_1.assertNonNegative)("offer.maxUnits", maxUnits);
|
|
73
|
-
(0, morpho_ts_1.assertNonNegative)("offer.maxAssets", maxAssets);
|
|
74
|
-
(0, morpho_ts_1.assertNonNegative)("offer.continuousFeeCap", continuousFeeCap);
|
|
75
|
-
index_js_2.OfferUtils.validateOfferCaps({ maxUnits, maxAssets });
|
|
76
|
-
const needsSettlementFee = maxUnits === 0n;
|
|
77
|
-
const timeToMaturity = needsSettlementFee
|
|
78
|
-
? BigInt(params.timeToMaturity)
|
|
79
|
-
: 0n;
|
|
80
|
-
if (needsSettlementFee) {
|
|
81
|
-
(0, morpho_ts_1.assertNonNegative)("timeToMaturity", timeToMaturity);
|
|
82
|
-
}
|
|
83
|
-
const chainId = await (0, utils_js_1.resolveChainId)(client);
|
|
84
|
-
const midnight = (0, morpho_ts_1.getChainAddress)(chainId, "midnight");
|
|
85
|
-
const consumed = (0, actions_1.readContract)(client, {
|
|
86
|
-
...(0, utils_js_1.callParameters)(params),
|
|
87
|
-
address: midnight,
|
|
88
|
-
abi: abis_js_1.midnightAbi,
|
|
89
|
-
functionName: "consumed",
|
|
90
|
-
args: [params.offer.maker, params.group],
|
|
91
|
-
});
|
|
92
|
-
const continuousFee = (0, actions_1.readContract)(client, {
|
|
93
|
-
...(0, utils_js_1.callParameters)(params),
|
|
94
|
-
address: midnight,
|
|
95
|
-
abi: abis_js_1.midnightAbi,
|
|
96
|
-
functionName: "continuousFee",
|
|
97
|
-
args: [params.marketId],
|
|
98
|
-
});
|
|
99
|
-
const [consumedValue, marketContinuousFee] = await Promise.all([
|
|
100
|
-
consumed,
|
|
101
|
-
continuousFee,
|
|
102
|
-
]);
|
|
103
|
-
if (continuousFeeCap < BigInt(marketContinuousFee))
|
|
104
|
-
return 0n;
|
|
105
|
-
const settlementFee = needsSettlementFee
|
|
106
|
-
? await (0, actions_1.readContract)(client, {
|
|
107
|
-
...(0, utils_js_1.callParameters)(params),
|
|
108
|
-
address: midnight,
|
|
109
|
-
abi: abis_js_1.midnightAbi,
|
|
110
|
-
functionName: "settlementFee",
|
|
111
|
-
args: [params.marketId, timeToMaturity],
|
|
112
|
-
})
|
|
113
|
-
: 0n;
|
|
114
|
-
return index_js_1.ConsumableUnitsLib.consumableUnits({
|
|
115
|
-
offer: params.offer,
|
|
116
|
-
consumed: consumedValue,
|
|
117
|
-
settlementFee,
|
|
118
|
-
});
|
|
119
|
-
}
|