@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,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,54 @@ 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) => GroupUtils.isGroupInput(entry)
|
|
124
|
+
? Group.from(entry).offers
|
|
125
|
+
: [
|
|
126
|
+
new Offer({
|
|
127
|
+
...Offer.from(entry),
|
|
128
|
+
group: OfferUtils.groupHash(entry),
|
|
129
|
+
}),
|
|
130
|
+
]);
|
|
131
|
+
if (!("paddedOffers" in params.tree)) {
|
|
132
|
+
buildDescriptor(offers, { preserveStandaloneGroups: true });
|
|
133
|
+
}
|
|
134
|
+
items = offers.map((offer) => ({
|
|
135
|
+
offer,
|
|
136
|
+
ratifierData: "0x",
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
else if (params.ratification.type === "ecrecover") {
|
|
140
|
+
if (params.ratification.signature != null) {
|
|
141
|
+
items = await EcrecoverRatifierUtils.ratify({
|
|
142
|
+
tree: params.tree,
|
|
143
|
+
signature: params.ratification.signature,
|
|
144
|
+
account: params.ratification.account,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
items = await EcrecoverRatifierUtils.ratify({
|
|
149
|
+
tree: params.tree,
|
|
150
|
+
client: params.ratification.client,
|
|
151
|
+
account: params.ratification.account,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
items = SetterRatifierUtils.ratify({ tree: params.tree });
|
|
157
|
+
}
|
|
158
|
+
const payload = await Payload.encode(items);
|
|
159
|
+
const validation = await MidnightApi.validateMempoolPayload({
|
|
169
160
|
baseUrl: params.apiUrl,
|
|
170
161
|
fetch: params.fetch,
|
|
171
162
|
request: params.request,
|
|
@@ -173,6 +164,10 @@ export var TreeUtils;
|
|
|
173
164
|
timestamp: params.timestamp,
|
|
174
165
|
payload,
|
|
175
166
|
});
|
|
167
|
+
if (!validation.valid) {
|
|
168
|
+
throw new MidnightMempoolValidationError(validation.issues);
|
|
169
|
+
}
|
|
170
|
+
return { valid: true, issues: validation.issues };
|
|
176
171
|
}
|
|
177
172
|
TreeUtils.mempoolValidate = mempoolValidate;
|
|
178
173
|
/**
|
|
@@ -208,6 +203,7 @@ export var TreeUtils;
|
|
|
208
203
|
* make-side code.
|
|
209
204
|
*
|
|
210
205
|
* @param entries - Groups or standalone offers in leaf order.
|
|
206
|
+
* @param options.preserveStandaloneGroups - Whether standalone offer group ids should be preserved instead of normalized.
|
|
211
207
|
* @returns Tree descriptor.
|
|
212
208
|
* @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
|
|
213
209
|
* @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
|
|
@@ -218,12 +214,14 @@ export var TreeUtils;
|
|
|
218
214
|
*
|
|
219
215
|
* const offer = Offer.create({
|
|
220
216
|
* market: {
|
|
217
|
+
* chainId: 8453,
|
|
218
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
221
219
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
222
220
|
* collateralParams: [
|
|
223
221
|
* {
|
|
224
222
|
* token: "0x0000000000000000000000000000000000007000",
|
|
225
223
|
* lltv: 770000000000000000n,
|
|
226
|
-
*
|
|
224
|
+
* liquidationCursor: 250000000000000000n,
|
|
227
225
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
228
226
|
* },
|
|
229
227
|
* ],
|
|
@@ -243,10 +241,17 @@ export var TreeUtils;
|
|
|
243
241
|
* console.log(tree.root);
|
|
244
242
|
* ```
|
|
245
243
|
*/
|
|
246
|
-
function buildDescriptor(entries) {
|
|
247
|
-
const structs = entries.flatMap((entry) =>
|
|
244
|
+
function buildDescriptor(entries, options = {}) {
|
|
245
|
+
const structs = entries.flatMap((entry) => GroupUtils.isGroupInput(entry)
|
|
248
246
|
? GroupUtils.toStructs(entry)
|
|
249
|
-
: [
|
|
247
|
+
: [
|
|
248
|
+
OfferUtils.toStruct({
|
|
249
|
+
offer: entry,
|
|
250
|
+
group: options.preserveStandaloneGroups
|
|
251
|
+
? undefined
|
|
252
|
+
: OfferUtils.groupHash(entry),
|
|
253
|
+
}),
|
|
254
|
+
]);
|
|
250
255
|
if (structs.length === 0) {
|
|
251
256
|
throw new InvalidTreeError("Tree must not be empty.");
|
|
252
257
|
}
|
|
@@ -290,12 +295,14 @@ export var TreeUtils;
|
|
|
290
295
|
*
|
|
291
296
|
* const offer = Offer.create({
|
|
292
297
|
* market: {
|
|
298
|
+
* chainId: 8453,
|
|
299
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
293
300
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
294
301
|
* collateralParams: [
|
|
295
302
|
* {
|
|
296
303
|
* token: "0x0000000000000000000000000000000000007000",
|
|
297
304
|
* lltv: 770000000000000000n,
|
|
298
|
-
*
|
|
305
|
+
* liquidationCursor: 250000000000000000n,
|
|
299
306
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
300
307
|
* },
|
|
301
308
|
* ],
|
|
@@ -326,7 +333,7 @@ export var TreeUtils;
|
|
|
326
333
|
* built-in Ecrecover and Setter helpers call this while generating
|
|
327
334
|
* `ratifierData`.
|
|
328
335
|
*
|
|
329
|
-
* @param params.tree - Tree that
|
|
336
|
+
* @param params.tree - Tree-like data with the root and leaves that contain the leaf.
|
|
330
337
|
* @param params.leafIndex - Leaf index to prove.
|
|
331
338
|
* @returns Proof descriptor.
|
|
332
339
|
* @throws {InvalidTreeError} when leaf index is out of range.
|
|
@@ -337,12 +344,14 @@ export var TreeUtils;
|
|
|
337
344
|
*
|
|
338
345
|
* const offer = Offer.create({
|
|
339
346
|
* market: {
|
|
347
|
+
* chainId: 8453,
|
|
348
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
340
349
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
341
350
|
* collateralParams: [
|
|
342
351
|
* {
|
|
343
352
|
* token: "0x0000000000000000000000000000000000007000",
|
|
344
353
|
* lltv: 770000000000000000n,
|
|
345
|
-
*
|
|
354
|
+
* liquidationCursor: 250000000000000000n,
|
|
346
355
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
347
356
|
* },
|
|
348
357
|
* ],
|
|
@@ -367,8 +376,7 @@ export var TreeUtils;
|
|
|
367
376
|
*/
|
|
368
377
|
function buildProof(params) {
|
|
369
378
|
const leafIndex = BigInt(params.leafIndex);
|
|
370
|
-
if (leafIndex < 0n ||
|
|
371
|
-
leafIndex >= BigInt(params.tree.paddedOffers.length)) {
|
|
379
|
+
if (leafIndex < 0n || leafIndex >= BigInt(params.tree.leaves.length)) {
|
|
372
380
|
throw new InvalidTreeError(`Leaf index "${leafIndex}" is outside the tree.`);
|
|
373
381
|
}
|
|
374
382
|
let index = Number(leafIndex);
|
|
@@ -405,12 +413,14 @@ export var TreeUtils;
|
|
|
405
413
|
*
|
|
406
414
|
* const offer = Offer.create({
|
|
407
415
|
* market: {
|
|
416
|
+
* chainId: 8453,
|
|
417
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
408
418
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
409
419
|
* collateralParams: [
|
|
410
420
|
* {
|
|
411
421
|
* token: "0x0000000000000000000000000000000000007000",
|
|
412
422
|
* lltv: 770000000000000000n,
|
|
413
|
-
*
|
|
423
|
+
* liquidationCursor: 250000000000000000n,
|
|
414
424
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
415
425
|
* },
|
|
416
426
|
* ],
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Hash } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Hashes EIP-712 digest parts as `keccak256(0x1901 || domainSeparator || structHash)`.
|
|
4
|
+
*
|
|
5
|
+
* Use this when the domain separator and struct hash are already available and
|
|
6
|
+
* rebuilding full typed-data values would duplicate protocol-specific type maps.
|
|
7
|
+
*
|
|
8
|
+
* @param domainSeparator - EIP-712 domain separator hash.
|
|
9
|
+
* @param structHash - EIP-712 struct hash.
|
|
10
|
+
* @returns Canonical EIP-712 digest.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { eip712Digest } from "@morpho-org/midnight-sdk";
|
|
14
|
+
*
|
|
15
|
+
* const digest = eip712Digest(
|
|
16
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
17
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000002",
|
|
18
|
+
* );
|
|
19
|
+
* console.log(digest);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare const eip712Digest: (domainSeparator: Hash, structHash: Hash) => Hash;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { concat, keccak256 } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Hashes EIP-712 digest parts as `keccak256(0x1901 || domainSeparator || structHash)`.
|
|
4
|
+
*
|
|
5
|
+
* Use this when the domain separator and struct hash are already available and
|
|
6
|
+
* rebuilding full typed-data values would duplicate protocol-specific type maps.
|
|
7
|
+
*
|
|
8
|
+
* @param domainSeparator - EIP-712 domain separator hash.
|
|
9
|
+
* @param structHash - EIP-712 struct hash.
|
|
10
|
+
* @returns Canonical EIP-712 digest.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { eip712Digest } from "@morpho-org/midnight-sdk";
|
|
14
|
+
*
|
|
15
|
+
* const digest = eip712Digest(
|
|
16
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
17
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000002",
|
|
18
|
+
* );
|
|
19
|
+
* console.log(digest);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const eip712Digest = (domainSeparator, structHash) => keccak256(concat(["0x1901", domainSeparator, structHash]));
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./EcrecoverRatifierUtils.js";
|
|
2
|
+
export * from "./eip712.js";
|
|
2
3
|
export * from "./Group.js";
|
|
3
4
|
export * from "./GroupUtils.js";
|
|
5
|
+
export { Payload } from "./Payload.js";
|
|
4
6
|
export * from "./RatifierUtils.js";
|
|
5
7
|
export * from "./SetterRatifierUtils.js";
|
|
6
8
|
export * from "./Tree.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./EcrecoverRatifierUtils.js";
|
|
2
|
+
export * from "./eip712.js";
|
|
2
3
|
export * from "./Group.js";
|
|
3
4
|
export * from "./GroupUtils.js";
|
|
5
|
+
export { Payload } from "./Payload.js";
|
|
4
6
|
export * from "./RatifierUtils.js";
|
|
5
7
|
export * from "./SetterRatifierUtils.js";
|
|
6
8
|
export * from "./Tree.js";
|
|
@@ -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.1.1",
|
|
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",
|
|
@@ -14,16 +17,24 @@
|
|
|
14
17
|
},
|
|
15
18
|
"license": "MIT",
|
|
16
19
|
"type": "module",
|
|
17
|
-
"main": "
|
|
20
|
+
"main": "./lib/cjs/index.js",
|
|
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": {
|
|
24
35
|
"*": {
|
|
25
36
|
"api": [
|
|
26
|
-
"
|
|
37
|
+
"lib/esm/api/index.d.ts"
|
|
27
38
|
]
|
|
28
39
|
}
|
|
29
40
|
},
|
|
@@ -31,6 +42,18 @@
|
|
|
31
42
|
"files": [
|
|
32
43
|
"lib"
|
|
33
44
|
],
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@morpho-org/morpho-ts": "^2.8.0",
|
|
47
|
+
"viem": "^2.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"fast-check": "^4.8.0",
|
|
51
|
+
"typescript": "^6.0.3",
|
|
52
|
+
"viem": "^2.54.2",
|
|
53
|
+
"vitest": "^4.1.9",
|
|
54
|
+
"@morpho-org/morpho-ts": "^2.8.0",
|
|
55
|
+
"@morpho-org/test": "^2.8.2"
|
|
56
|
+
},
|
|
34
57
|
"scripts": {
|
|
35
58
|
"prepublish": "$npm_execpath build",
|
|
36
59
|
"compile": "node ../../scripts/compile-solidity.js midnight-sdk",
|
|
@@ -39,31 +62,5 @@
|
|
|
39
62
|
"build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
|
|
40
63
|
"test": "vitest --root ../.. --project midnight-sdk"
|
|
41
64
|
},
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
"viem": "^2.0.0"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@morpho-org/morpho-ts": "workspace:^",
|
|
48
|
-
"@morpho-org/test": "workspace:^",
|
|
49
|
-
"fast-check": "^4.4.0",
|
|
50
|
-
"typescript": "^6.0.3",
|
|
51
|
-
"viem": "2.52.2",
|
|
52
|
-
"vitest": "^4.1.6"
|
|
53
|
-
},
|
|
54
|
-
"publishConfig": {
|
|
55
|
-
"exports": {
|
|
56
|
-
".": {
|
|
57
|
-
"types": "./lib/esm/index.d.ts",
|
|
58
|
-
"import": "./lib/esm/index.js",
|
|
59
|
-
"require": "./lib/cjs/index.js"
|
|
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
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
65
|
+
"types": "./lib/esm/index.d.ts"
|
|
66
|
+
}
|
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>;
|