@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
|
@@ -6,28 +6,33 @@ const viem_1 = require("viem");
|
|
|
6
6
|
const actions_1 = require("viem/actions");
|
|
7
7
|
const constants_js_1 = require("../constants.js");
|
|
8
8
|
const errors_js_1 = require("../errors.js");
|
|
9
|
+
const index_js_1 = require("../market/index.js");
|
|
10
|
+
const index_js_2 = require("../offers/index.js");
|
|
11
|
+
const eip712_js_1 = require("./eip712.js");
|
|
12
|
+
const RatifierUtils_js_1 = require("./RatifierUtils.js");
|
|
13
|
+
const TreeUtils_js_1 = require("./TreeUtils.js");
|
|
9
14
|
const treeTypeHashes = [
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
15
|
+
"0x270da1ebafc0f24637af3612fb8c3a1d828fcb56d3637c24e86dd006b12ca7f9",
|
|
16
|
+
"0x828b9cdf8326a1cf234328e4d5229546a98fb72ef73624f5b6b31538e555b96c",
|
|
17
|
+
"0xfcb7a3ca4094246b8185620c4cf025c93032b6f0384805aa3f22afe04290e982",
|
|
18
|
+
"0xcc97cb1955496a5269b5a7afca62ba694edcab26ba838a1adbd257931249de92",
|
|
19
|
+
"0xda3feb08db360ad9e09540132ff04d2b6a596fdaa4747892217aaa4c7c9bcc31",
|
|
20
|
+
"0x15bd6e2aa1a7a61614187ac16d2cbf8610c8f2f3c3d9eaa380ae7a501ee3cf06",
|
|
21
|
+
"0xb726cb7fab1a24c28213cbd482fa5a301f127fb25feb01da341919983a72711a",
|
|
22
|
+
"0xcea9cd557c6f821868ea287304199d0e0554af630bfa8fe36c64eb3bbacca418",
|
|
23
|
+
"0xf7dbde8234e8e345cec8fc0a8ac5909ee336b214882751ecd51e7b37df4f6cdd",
|
|
24
|
+
"0x5400a5d43d39e6bfe910af8cb84ac77bf501d310413769dffd62ccecda8b00c6",
|
|
25
|
+
"0x0754209b60d99d0822b3ecd5a970f9db09df9c8998a8441e24b81f06d6c76fee",
|
|
26
|
+
"0xf5d561d88647c3b38ed6636709d3166819fc66f8ed52a0daf4ae186387b4646c",
|
|
27
|
+
"0x5801c07a6c7df039ce00a7a2b8bd92aa1cf333c30b0bc3d78768590b6063d09e",
|
|
28
|
+
"0xc9da7190eaf4b14c7cb1c14f9898256c0adb6b1dc303afe79594dea64fe199c0",
|
|
29
|
+
"0xa47534c85ac57c583568465d40fd46683d2d558d8129fe1aca01e93023afca92",
|
|
30
|
+
"0xb1e841691fb54f4ef85e2ed9de45d610e57f49e1e6eb2510ceead16e447dd519",
|
|
31
|
+
"0x4fa4f16f09f0c36c7670449a4032073380d28a60071e12ee8874bb3e5a8318fc",
|
|
32
|
+
"0x817bbaac8bb863670f488b454cdd5d0990d9d81871a68e9df381c3c13d3f2ba2",
|
|
33
|
+
"0xc447f06079bddf4b011523c4bce119e9e90fdf937de4ee88f48010406560e9c1",
|
|
34
|
+
"0x1608d5eb56943c667c34b413f9f8a1c24a84ddfe1301a9c25487e638de1f5822",
|
|
35
|
+
"0x3a677100d2e855c24a62d1e9c365bff90d02287f066a07064843ca1ee70ea113",
|
|
31
36
|
];
|
|
32
37
|
const signatureAbi = [
|
|
33
38
|
{
|
|
@@ -59,10 +64,12 @@ const typedDataTypes = {
|
|
|
59
64
|
CollateralParams: [
|
|
60
65
|
{ name: "token", type: "address" },
|
|
61
66
|
{ name: "lltv", type: "uint256" },
|
|
62
|
-
{ name: "
|
|
67
|
+
{ name: "liquidationCursor", type: "uint256" },
|
|
63
68
|
{ name: "oracle", type: "address" },
|
|
64
69
|
],
|
|
65
70
|
Market: [
|
|
71
|
+
{ name: "chainId", type: "uint256" },
|
|
72
|
+
{ name: "midnight", type: "address" },
|
|
66
73
|
{ name: "loanToken", type: "address" },
|
|
67
74
|
{ name: "collateralParams", type: "CollateralParams[]" },
|
|
68
75
|
{ name: "maturity", type: "uint256" },
|
|
@@ -83,8 +90,8 @@ const typedDataTypes = {
|
|
|
83
90
|
{ name: "receiverIfMakerIsSeller", type: "address" },
|
|
84
91
|
{ name: "ratifier", type: "address" },
|
|
85
92
|
{ name: "reduceOnly", type: "bool" },
|
|
86
|
-
{ name: "maxUnits", type: "
|
|
87
|
-
{ name: "maxAssets", type: "
|
|
93
|
+
{ name: "maxUnits", type: "uint128" },
|
|
94
|
+
{ name: "maxAssets", type: "uint128" },
|
|
88
95
|
{ name: "continuousFeeCap", type: "uint256" },
|
|
89
96
|
],
|
|
90
97
|
};
|
|
@@ -97,21 +104,13 @@ const buildTreeValue = (offers) => {
|
|
|
97
104
|
buildTreeValue(offers.slice(mid)),
|
|
98
105
|
];
|
|
99
106
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const comparableRatifier = ratifier.toLowerCase();
|
|
108
|
-
for (const offer of offers.slice(1)) {
|
|
109
|
-
if (offer.ratifier.toLowerCase() !== comparableRatifier) {
|
|
110
|
-
throw new errors_js_1.InvalidTreeError(`All offers in an Ecrecover tree must use one ratifier; expected "${ratifier}", got "${offer.ratifier}". Build separate trees per ratifier.`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return ratifier;
|
|
114
|
-
};
|
|
107
|
+
function toCanonicalYParity(v) {
|
|
108
|
+
if (v === 27)
|
|
109
|
+
return 0;
|
|
110
|
+
if (v === 28)
|
|
111
|
+
return 1;
|
|
112
|
+
throw new errors_js_1.InvalidEcrecoverSignatureVError(v);
|
|
113
|
+
}
|
|
115
114
|
/**
|
|
116
115
|
* EcrecoverRatifier-specific pure utilities.
|
|
117
116
|
*
|
|
@@ -120,7 +119,10 @@ const getTreeRatifier = (tree) => {
|
|
|
120
119
|
* validate the tree, sign the typed data, call `ratify`, then pass the returned
|
|
121
120
|
* items to `Payload.encode`. Ecrecover trees must contain one ratifier; split
|
|
122
121
|
* trees by ratifier before signing. The signer may be the maker or an address
|
|
123
|
-
* authorized by every maker in the tree.
|
|
122
|
+
* authorized by every maker in the tree. Ratifier helpers accept tree-like
|
|
123
|
+
* inputs rather than requiring the `Tree` class. Passing an existing `Tree`
|
|
124
|
+
* remains the optimal path because its cached offers, leaves, root, and height
|
|
125
|
+
* are reused for typed data and per-leaf proofs.
|
|
124
126
|
*
|
|
125
127
|
* @example
|
|
126
128
|
* ```ts
|
|
@@ -152,14 +154,14 @@ var EcrecoverRatifierUtils;
|
|
|
152
154
|
}
|
|
153
155
|
EcrecoverRatifierUtils.treeTypeHash = treeTypeHash;
|
|
154
156
|
/**
|
|
155
|
-
* Builds EcrecoverRatifier typed data for a tree.
|
|
157
|
+
* Builds EcrecoverRatifier typed data for a tree-like input.
|
|
156
158
|
*
|
|
157
159
|
* Use after the tree is built and validated, before requesting the signer
|
|
158
160
|
* signature. The EIP-712 verifier is derived from the shared ratifier address
|
|
159
161
|
* on the tree offers. `ratify` calls this for you when given a client and
|
|
160
162
|
* account.
|
|
161
163
|
*
|
|
162
|
-
* @param params.tree - Ecrecover-ratified offer tree to sign.
|
|
164
|
+
* @param params.tree - Ecrecover-ratified offer tree-like input to sign.
|
|
163
165
|
* @param params.chainId - EIP-155 chain id included in the EIP-712 domain.
|
|
164
166
|
* @returns EIP-712 typed-data descriptor.
|
|
165
167
|
* @throws {InvalidTreeError} when the tree is invalid or contains multiple ratifiers.
|
|
@@ -172,12 +174,14 @@ var EcrecoverRatifierUtils;
|
|
|
172
174
|
*
|
|
173
175
|
* const offer = Offer.create({
|
|
174
176
|
* market: {
|
|
177
|
+
* chainId: 8453,
|
|
178
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
175
179
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
176
180
|
* collateralParams: [
|
|
177
181
|
* {
|
|
178
182
|
* token: "0x0000000000000000000000000000000000007000",
|
|
179
183
|
* lltv: 770000000000000000n,
|
|
180
|
-
*
|
|
184
|
+
* liquidationCursor: 250000000000000000n,
|
|
181
185
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
182
186
|
* },
|
|
183
187
|
* ],
|
|
@@ -202,10 +206,11 @@ var EcrecoverRatifierUtils;
|
|
|
202
206
|
* ```
|
|
203
207
|
*/
|
|
204
208
|
function typedData(params) {
|
|
205
|
-
const verifyingContract =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
const { tree, ratifier: verifyingContract } = RatifierUtils_js_1.RatifierUtils.normalizeRatifierTree({
|
|
210
|
+
tree: params.tree,
|
|
211
|
+
label: "Ecrecover",
|
|
212
|
+
});
|
|
213
|
+
const treeType = tree.height === 0 ? "Offer" : `Offer${"[2]".repeat(tree.height)}`;
|
|
209
214
|
return (0, morpho_ts_1.deepFreeze)({
|
|
210
215
|
domain: {
|
|
211
216
|
chainId: BigInt(params.chainId),
|
|
@@ -217,7 +222,7 @@ var EcrecoverRatifierUtils;
|
|
|
217
222
|
},
|
|
218
223
|
primaryType: "OfferTree",
|
|
219
224
|
message: {
|
|
220
|
-
offerTree: buildTreeValue(
|
|
225
|
+
offerTree: buildTreeValue(tree.paddedOffers),
|
|
221
226
|
},
|
|
222
227
|
});
|
|
223
228
|
}
|
|
@@ -225,7 +230,7 @@ var EcrecoverRatifierUtils;
|
|
|
225
230
|
/**
|
|
226
231
|
* Builds the EcrecoverRatifier digest used by the Solidity ratifier.
|
|
227
232
|
*
|
|
228
|
-
* @param params.tree - Ecrecover-ratified offer tree to hash.
|
|
233
|
+
* @param params.tree - Ecrecover-ratified offer tree-like input to hash.
|
|
229
234
|
* @param params.chainId - EIP-155 chain id included in the EIP-712 domain.
|
|
230
235
|
* @returns EIP-712 digest.
|
|
231
236
|
* @throws {InvalidTreeError} when the tree contains multiple ratifiers.
|
|
@@ -238,12 +243,14 @@ var EcrecoverRatifierUtils;
|
|
|
238
243
|
*
|
|
239
244
|
* const offer = Offer.create({
|
|
240
245
|
* market: {
|
|
246
|
+
* chainId: 8453,
|
|
247
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
241
248
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
242
249
|
* collateralParams: [
|
|
243
250
|
* {
|
|
244
251
|
* token: "0x0000000000000000000000000000000000007000",
|
|
245
252
|
* lltv: 770000000000000000n,
|
|
246
|
-
*
|
|
253
|
+
* liquidationCursor: 250000000000000000n,
|
|
247
254
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
248
255
|
* },
|
|
249
256
|
* ],
|
|
@@ -268,19 +275,161 @@ var EcrecoverRatifierUtils;
|
|
|
268
275
|
* ```
|
|
269
276
|
*/
|
|
270
277
|
function digest(params) {
|
|
271
|
-
const verifyingContract =
|
|
278
|
+
const { tree, ratifier: verifyingContract } = RatifierUtils_js_1.RatifierUtils.normalizeRatifierTree({
|
|
279
|
+
tree: params.tree,
|
|
280
|
+
label: "Ecrecover",
|
|
281
|
+
});
|
|
272
282
|
const domainSeparator = (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)(domainSeparatorAbi, [
|
|
273
283
|
constants_js_1.EIP712_DOMAIN_TYPEHASH,
|
|
274
284
|
BigInt(params.chainId),
|
|
275
285
|
verifyingContract,
|
|
276
286
|
]));
|
|
277
287
|
const structHash = (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)(treeStructHashAbi, [
|
|
278
|
-
treeTypeHash(
|
|
279
|
-
|
|
288
|
+
treeTypeHash(tree.height),
|
|
289
|
+
tree.root,
|
|
280
290
|
]));
|
|
281
|
-
return (0,
|
|
291
|
+
return (0, eip712_js_1.eip712Digest)(domainSeparator, structHash);
|
|
282
292
|
}
|
|
283
293
|
EcrecoverRatifierUtils.digest = digest;
|
|
294
|
+
/**
|
|
295
|
+
* Builds the EcrecoverRatifier digest from a payload offer, root, and proof height.
|
|
296
|
+
*
|
|
297
|
+
* Use this on the take-side or in indexers after decoding ratifier data, when
|
|
298
|
+
* the original full tree is not available but the payload item includes the
|
|
299
|
+
* offer and proof metadata needed to reconstruct the signed digest. Pass the
|
|
300
|
+
* observed log or execution chain id so cross-chain-spoofed payloads are
|
|
301
|
+
* rejected before signature recovery.
|
|
302
|
+
*
|
|
303
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
304
|
+
* @param params.offer - Offer carried by the payload item.
|
|
305
|
+
* @param params.root - Merkle root embedded in the ratifier data.
|
|
306
|
+
* @param params.proofLength - Number of sibling hashes in the Merkle proof.
|
|
307
|
+
* @returns EIP-712 digest signed by the maker or authorized signer.
|
|
308
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
309
|
+
* @throws {InvalidTreeHeightError} when `proofLength` exceeds 20.
|
|
310
|
+
* @example
|
|
311
|
+
* ```ts
|
|
312
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
313
|
+
* import { zeroHash } from "viem";
|
|
314
|
+
*
|
|
315
|
+
* const digest = EcrecoverRatifierUtils.digestForRoot({
|
|
316
|
+
* chainId: 8453n,
|
|
317
|
+
* offer,
|
|
318
|
+
* root: zeroHash,
|
|
319
|
+
* proofLength: 0,
|
|
320
|
+
* });
|
|
321
|
+
* console.log(digest);
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
function digestForRoot(params) {
|
|
325
|
+
const offer = index_js_2.Offer.from(params.offer);
|
|
326
|
+
const market = index_js_1.MarketParams.from(offer.market);
|
|
327
|
+
const chainId = BigInt(params.chainId);
|
|
328
|
+
if (chainId !== market.chainId) {
|
|
329
|
+
throw new errors_js_1.ChainIdMismatchError(Number(chainId), market.chainId);
|
|
330
|
+
}
|
|
331
|
+
const domainSeparator = (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)(domainSeparatorAbi, [
|
|
332
|
+
constants_js_1.EIP712_DOMAIN_TYPEHASH,
|
|
333
|
+
chainId,
|
|
334
|
+
offer.ratifier,
|
|
335
|
+
]));
|
|
336
|
+
const structHash = (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)(treeStructHashAbi, [
|
|
337
|
+
treeTypeHash(params.proofLength),
|
|
338
|
+
params.root,
|
|
339
|
+
]));
|
|
340
|
+
return (0, eip712_js_1.eip712Digest)(domainSeparator, structHash);
|
|
341
|
+
}
|
|
342
|
+
EcrecoverRatifierUtils.digestForRoot = digestForRoot;
|
|
343
|
+
/**
|
|
344
|
+
* Builds the EcrecoverRatifier digest from one payload item's encoded ratifier data.
|
|
345
|
+
*
|
|
346
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
347
|
+
* @param params.offer - Offer carried by the payload item.
|
|
348
|
+
* @param params.ratifierData - ABI-encoded Ecrecover ratifier data.
|
|
349
|
+
* @returns EIP-712 digest signed by the maker or authorized signer.
|
|
350
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
351
|
+
* @throws {InvalidTreeHeightError} when the proof height exceeds 20.
|
|
352
|
+
* @example
|
|
353
|
+
* ```ts
|
|
354
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
355
|
+
*
|
|
356
|
+
* const digest = EcrecoverRatifierUtils.digestRatifierData({
|
|
357
|
+
* chainId: 8453n,
|
|
358
|
+
* offer,
|
|
359
|
+
* ratifierData,
|
|
360
|
+
* });
|
|
361
|
+
* console.log(digest);
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
function digestRatifierData(params) {
|
|
365
|
+
const decoded = decodeRatifierData(params.ratifierData);
|
|
366
|
+
return digestForRoot({
|
|
367
|
+
chainId: params.chainId,
|
|
368
|
+
offer: params.offer,
|
|
369
|
+
root: decoded.root,
|
|
370
|
+
proofLength: decoded.proof.length,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
EcrecoverRatifierUtils.digestRatifierData = digestRatifierData;
|
|
374
|
+
/**
|
|
375
|
+
* Verifies an Ecrecover ratifier-data proof and recovers its signer.
|
|
376
|
+
*
|
|
377
|
+
* This helper intentionally does not check `Midnight.isAuthorized` or
|
|
378
|
+
* `EcrecoverRatifier.isRootCanceled` state. Consumers must query both at the
|
|
379
|
+
* observed block before treating a recovered item as executable: the returned
|
|
380
|
+
* signer must be the maker or authorized by the maker, the offer ratifier must
|
|
381
|
+
* be authorized by the maker, and `isRootCanceled(maker, root)` must be false.
|
|
382
|
+
*
|
|
383
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
384
|
+
* @param params.offer - Offer carried by the payload item.
|
|
385
|
+
* @param params.ratifierData - ABI-encoded Ecrecover ratifier data.
|
|
386
|
+
* @returns Decoded ratifier data plus recovered signer.
|
|
387
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
388
|
+
* @throws {InvalidEcrecoverSignatureVError} when the decoded signature `v` is not 27 or 28.
|
|
389
|
+
* @throws {InvalidTreeError} when the proof does not include `offer` in `root`.
|
|
390
|
+
* @throws {InvalidTreeHeightError} when the proof height exceeds 20.
|
|
391
|
+
* @example
|
|
392
|
+
* ```ts
|
|
393
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
394
|
+
*
|
|
395
|
+
* const verified = await EcrecoverRatifierUtils.verifyRatifierData({
|
|
396
|
+
* chainId: 8453n,
|
|
397
|
+
* offer,
|
|
398
|
+
* ratifierData,
|
|
399
|
+
* });
|
|
400
|
+
* console.log(verified.signer);
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
async function verifyRatifierData(params) {
|
|
404
|
+
const offer = index_js_2.Offer.from(params.offer);
|
|
405
|
+
const decoded = decodeRatifierData(params.ratifierData);
|
|
406
|
+
if (!TreeUtils_js_1.TreeUtils.verifyProof({
|
|
407
|
+
offer,
|
|
408
|
+
root: decoded.root,
|
|
409
|
+
leafIndex: decoded.leafIndex,
|
|
410
|
+
proof: decoded.proof,
|
|
411
|
+
})) {
|
|
412
|
+
throw new errors_js_1.InvalidTreeError("Ratifier data proof does not include offer.");
|
|
413
|
+
}
|
|
414
|
+
const signer = await (0, viem_1.recoverAddress)({
|
|
415
|
+
hash: digestForRoot({
|
|
416
|
+
chainId: params.chainId,
|
|
417
|
+
offer,
|
|
418
|
+
root: decoded.root,
|
|
419
|
+
proofLength: decoded.proof.length,
|
|
420
|
+
}),
|
|
421
|
+
signature: (0, viem_1.serializeSignature)({
|
|
422
|
+
r: decoded.signature.r,
|
|
423
|
+
s: decoded.signature.s,
|
|
424
|
+
yParity: toCanonicalYParity(decoded.signature.v),
|
|
425
|
+
}),
|
|
426
|
+
});
|
|
427
|
+
return (0, morpho_ts_1.deepFreeze)({
|
|
428
|
+
...decoded,
|
|
429
|
+
signer,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
EcrecoverRatifierUtils.verifyRatifierData = verifyRatifierData;
|
|
284
433
|
/**
|
|
285
434
|
* Signs EcrecoverRatifier typed data through a viem client.
|
|
286
435
|
*
|
|
@@ -289,12 +438,13 @@ var EcrecoverRatifierUtils;
|
|
|
289
438
|
* client and account. The account may be the maker or an address authorized
|
|
290
439
|
* by every maker in the tree; the protocol checks that authorization onchain.
|
|
291
440
|
*
|
|
292
|
-
* @param params.tree - Ecrecover-ratified offer tree to sign.
|
|
441
|
+
* @param params.tree - Ecrecover-ratified offer tree-like input to sign.
|
|
293
442
|
* @param params.client - Viem client whose transport signs the tree typed data.
|
|
294
443
|
* @param params.account - Account used to sign the tree typed data.
|
|
295
444
|
* @returns Signature returned by the client.
|
|
296
|
-
* @throws {InvalidTreeError} when the tree is invalid or
|
|
445
|
+
* @throws {InvalidTreeError} when the tree is invalid, contains multiple ratifiers, or spans multiple chain ids.
|
|
297
446
|
* @throws {InvalidTreeHeightError} when the tree height is unsupported.
|
|
447
|
+
* @throws {ChainIdMismatchError} when `params.client.chain?.id` does not match the tree offer chain id.
|
|
298
448
|
* @throws {InvalidTypedDataSignatureError} when the returned signature does not recover to `params.account`.
|
|
299
449
|
* @example
|
|
300
450
|
* ```ts
|
|
@@ -305,12 +455,14 @@ var EcrecoverRatifierUtils;
|
|
|
305
455
|
*
|
|
306
456
|
* const offer = Offer.create({
|
|
307
457
|
* market: {
|
|
458
|
+
* chainId: 8453,
|
|
459
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
308
460
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
309
461
|
* collateralParams: [
|
|
310
462
|
* {
|
|
311
463
|
* token: "0x0000000000000000000000000000000000007000",
|
|
312
464
|
* lltv: 770000000000000000n,
|
|
313
|
-
*
|
|
465
|
+
* liquidationCursor: 250000000000000000n,
|
|
314
466
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
315
467
|
* },
|
|
316
468
|
* ],
|
|
@@ -340,24 +492,46 @@ var EcrecoverRatifierUtils;
|
|
|
340
492
|
* ```
|
|
341
493
|
*/
|
|
342
494
|
async function sign(params) {
|
|
495
|
+
const { tree } = RatifierUtils_js_1.RatifierUtils.normalizeRatifierTree({
|
|
496
|
+
tree: params.tree,
|
|
497
|
+
label: "Ecrecover",
|
|
498
|
+
});
|
|
499
|
+
const expectedChainId = index_js_1.MarketParams.from(tree.offers[0].market).chainId;
|
|
500
|
+
for (const offer of tree.offers.slice(1)) {
|
|
501
|
+
const offerChainId = index_js_1.MarketParams.from(offer.market).chainId;
|
|
502
|
+
if (offerChainId !== expectedChainId) {
|
|
503
|
+
throw new errors_js_1.InvalidTreeError(`All offers in an Ecrecover tree must use one chain id; expected "${expectedChainId}", got "${offerChainId}". Build separate trees per chain.`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const clientChainId = params.client.chain?.id;
|
|
507
|
+
if (clientChainId == null || BigInt(clientChainId) !== expectedChainId) {
|
|
508
|
+
throw new errors_js_1.ChainIdMismatchError(clientChainId, expectedChainId);
|
|
509
|
+
}
|
|
343
510
|
const signer = typeof params.account === "string"
|
|
344
511
|
? params.account
|
|
345
512
|
: params.account.address;
|
|
346
513
|
const data = typedData({
|
|
347
|
-
tree
|
|
348
|
-
chainId:
|
|
514
|
+
tree,
|
|
515
|
+
chainId: expectedChainId,
|
|
349
516
|
});
|
|
350
517
|
const signature = await (0, actions_1.signTypedData)(params.client, {
|
|
351
518
|
account: params.account,
|
|
352
519
|
...data,
|
|
353
520
|
});
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
521
|
+
let isValidSignature = false;
|
|
522
|
+
try {
|
|
523
|
+
isValidSignature = await (0, viem_1.verifyHash)({
|
|
524
|
+
address: signer,
|
|
525
|
+
hash: digest({ tree, chainId: expectedChainId }),
|
|
526
|
+
signature,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
catch (cause) {
|
|
530
|
+
throw new errors_js_1.InvalidTypedDataSignatureError(signer, cause);
|
|
531
|
+
}
|
|
532
|
+
if (!isValidSignature) {
|
|
360
533
|
throw new errors_js_1.InvalidTypedDataSignatureError(signer);
|
|
534
|
+
}
|
|
361
535
|
return signature;
|
|
362
536
|
}
|
|
363
537
|
EcrecoverRatifierUtils.sign = sign;
|
|
@@ -381,17 +555,17 @@ var EcrecoverRatifierUtils;
|
|
|
381
555
|
*/
|
|
382
556
|
function toSignature(signature) {
|
|
383
557
|
if (typeof signature !== "string") {
|
|
558
|
+
const v = signature.v != null ? Number(signature.v) : Number(signature.yParity);
|
|
384
559
|
return {
|
|
385
|
-
v:
|
|
386
|
-
? Number(signature.v)
|
|
387
|
-
: Number(signature.yParity) + 27,
|
|
560
|
+
v: v < 27 ? v + 27 : v,
|
|
388
561
|
r: signature.r,
|
|
389
562
|
s: signature.s,
|
|
390
563
|
};
|
|
391
564
|
}
|
|
392
565
|
const parsed = (0, viem_1.parseSignature)(signature);
|
|
566
|
+
const v = Number(parsed.v ?? BigInt(parsed.yParity));
|
|
393
567
|
return {
|
|
394
|
-
v:
|
|
568
|
+
v: v < 27 ? v + 27 : v,
|
|
395
569
|
r: parsed.r,
|
|
396
570
|
s: parsed.s,
|
|
397
571
|
};
|
|
@@ -482,7 +656,7 @@ var EcrecoverRatifierUtils;
|
|
|
482
656
|
* Use after a tree has been signed when a caller needs data for one offer
|
|
483
657
|
* leaf. Use `ratify` to produce payload-ready items for the whole tree.
|
|
484
658
|
*
|
|
485
|
-
* @param params.tree - Ecrecover-ratified offer tree that produced the proof.
|
|
659
|
+
* @param params.tree - Ecrecover-ratified offer tree-like input that produced the proof.
|
|
486
660
|
* @param params.leafIndex - Leaf index to prove.
|
|
487
661
|
* @param params.signature - Ecrecover signature for the tree root.
|
|
488
662
|
* @returns ABI-encoded EcrecoverRatifier data.
|
|
@@ -494,12 +668,14 @@ var EcrecoverRatifierUtils;
|
|
|
494
668
|
*
|
|
495
669
|
* const offer = Offer.create({
|
|
496
670
|
* market: {
|
|
671
|
+
* chainId: 8453,
|
|
672
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
497
673
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
498
674
|
* collateralParams: [
|
|
499
675
|
* {
|
|
500
676
|
* token: "0x0000000000000000000000000000000000007000",
|
|
501
677
|
* lltv: 770000000000000000n,
|
|
502
|
-
*
|
|
678
|
+
* liquidationCursor: 250000000000000000n,
|
|
503
679
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
504
680
|
* },
|
|
505
681
|
* ],
|
|
@@ -524,8 +700,11 @@ var EcrecoverRatifierUtils;
|
|
|
524
700
|
* ```
|
|
525
701
|
*/
|
|
526
702
|
function ratifierData(params) {
|
|
527
|
-
|
|
528
|
-
|
|
703
|
+
const { tree } = RatifierUtils_js_1.RatifierUtils.normalizeRatifierTree({
|
|
704
|
+
tree: params.tree,
|
|
705
|
+
label: "Ecrecover",
|
|
706
|
+
});
|
|
707
|
+
const proof = TreeUtils_js_1.TreeUtils.buildProof({ tree, leafIndex: params.leafIndex });
|
|
529
708
|
return encodeRatifierData({
|
|
530
709
|
signature: toSignature(params.signature),
|
|
531
710
|
root: proof.root,
|
|
@@ -541,14 +720,14 @@ var EcrecoverRatifierUtils;
|
|
|
541
720
|
* The returned items preserve tree leaf order and include ratifier data
|
|
542
721
|
* required by takers. The group id is stored on each inline offer.
|
|
543
722
|
*
|
|
544
|
-
* @param params.tree - Ecrecover-ratified offer tree to ratify.
|
|
723
|
+
* @param params.tree - Ecrecover-ratified offer tree-like input to ratify.
|
|
545
724
|
* @param params.client - Optional viem client whose transport signs typed data built from `params.tree`.
|
|
546
725
|
* @param params.account - Optional account used to sign typed data built from `params.tree`.
|
|
547
726
|
* @param params.signature - Optional precomputed signature for `params.tree`.
|
|
548
727
|
* @returns Items containing each offer and its ratifier data.
|
|
549
728
|
* @throws {InvalidTreeError} when the tree is invalid or contains multiple ratifiers.
|
|
550
729
|
* @throws {InvalidTreeHeightError} when the tree height is unsupported.
|
|
551
|
-
* @throws {InvalidTypedDataSignatureError} when client signing
|
|
730
|
+
* @throws {InvalidTypedDataSignatureError} when client signing or a precomputed signature does not recover to `params.account`.
|
|
552
731
|
* @example
|
|
553
732
|
* ```ts
|
|
554
733
|
* import { EcrecoverRatifierUtils, Tree } from "@morpho-org/midnight-sdk";
|
|
@@ -558,12 +737,14 @@ var EcrecoverRatifierUtils;
|
|
|
558
737
|
*
|
|
559
738
|
* const offer = Offer.create({
|
|
560
739
|
* market: {
|
|
740
|
+
* chainId: 8453,
|
|
741
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
561
742
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
562
743
|
* collateralParams: [
|
|
563
744
|
* {
|
|
564
745
|
* token: "0x0000000000000000000000000000000000007000",
|
|
565
746
|
* lltv: 770000000000000000n,
|
|
566
|
-
*
|
|
747
|
+
* liquidationCursor: 250000000000000000n,
|
|
567
748
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
568
749
|
* },
|
|
569
750
|
* ],
|
|
@@ -593,20 +774,55 @@ var EcrecoverRatifierUtils;
|
|
|
593
774
|
* ```
|
|
594
775
|
*/
|
|
595
776
|
async function ratify(params) {
|
|
777
|
+
const { tree } = RatifierUtils_js_1.RatifierUtils.normalizeRatifierTree({
|
|
778
|
+
tree: params.tree,
|
|
779
|
+
label: "Ecrecover",
|
|
780
|
+
});
|
|
596
781
|
let signature;
|
|
597
782
|
if (params.signature != null) {
|
|
598
|
-
getTreeRatifier(params.tree);
|
|
599
783
|
signature = toSignature(params.signature);
|
|
784
|
+
const expectedChainId = index_js_1.MarketParams.from(tree.offers[0].market).chainId;
|
|
785
|
+
for (const offer of tree.offers.slice(1)) {
|
|
786
|
+
const offerChainId = index_js_1.MarketParams.from(offer.market).chainId;
|
|
787
|
+
if (offerChainId !== expectedChainId) {
|
|
788
|
+
throw new errors_js_1.InvalidTreeError(`All offers in an Ecrecover tree must use one chain id; expected "${expectedChainId}", got "${offerChainId}". Build separate trees per chain.`);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
const signer = typeof params.account === "string"
|
|
792
|
+
? params.account
|
|
793
|
+
: params.account.address;
|
|
794
|
+
let isValidSignature = false;
|
|
795
|
+
try {
|
|
796
|
+
isValidSignature = await (0, viem_1.verifyHash)({
|
|
797
|
+
address: signer,
|
|
798
|
+
hash: digest({ tree, chainId: expectedChainId }),
|
|
799
|
+
signature: (0, viem_1.serializeSignature)({
|
|
800
|
+
r: signature.r,
|
|
801
|
+
s: signature.s,
|
|
802
|
+
yParity: signature.v - 27,
|
|
803
|
+
}),
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
catch (cause) {
|
|
807
|
+
throw new errors_js_1.InvalidTypedDataSignatureError(signer, cause);
|
|
808
|
+
}
|
|
809
|
+
if (!isValidSignature) {
|
|
810
|
+
throw new errors_js_1.InvalidTypedDataSignatureError(signer);
|
|
811
|
+
}
|
|
600
812
|
}
|
|
601
813
|
else {
|
|
602
|
-
signature = toSignature(await sign(
|
|
814
|
+
signature = toSignature(await sign({
|
|
815
|
+
tree,
|
|
816
|
+
client: params.client,
|
|
817
|
+
account: params.account,
|
|
818
|
+
}));
|
|
603
819
|
}
|
|
604
820
|
const items = [];
|
|
605
|
-
for (const offer of
|
|
821
|
+
for (const offer of tree.offers) {
|
|
606
822
|
items.push({
|
|
607
823
|
offer,
|
|
608
824
|
ratifierData: ratifierData({
|
|
609
|
-
tree
|
|
825
|
+
tree,
|
|
610
826
|
leafIndex: items.length,
|
|
611
827
|
signature,
|
|
612
828
|
}),
|
|
@@ -18,12 +18,14 @@ import { type GroupInput, type IGroup } from "./GroupUtils.js";
|
|
|
18
18
|
*
|
|
19
19
|
* const offer = Offer.create({
|
|
20
20
|
* market: {
|
|
21
|
+
* chainId: 8453,
|
|
22
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
21
23
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
22
24
|
* collateralParams: [
|
|
23
25
|
* {
|
|
24
26
|
* token: "0x0000000000000000000000000000000000007000",
|
|
25
27
|
* lltv: 770000000000000000n,
|
|
26
|
-
*
|
|
28
|
+
* liquidationCursor: 250000000000000000n,
|
|
27
29
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
28
30
|
* },
|
|
29
31
|
* ],
|
|
@@ -61,12 +63,14 @@ export declare class Group implements IGroup {
|
|
|
61
63
|
*
|
|
62
64
|
* const offer = Offer.create({
|
|
63
65
|
* market: {
|
|
66
|
+
* chainId: 8453,
|
|
67
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
64
68
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
65
69
|
* collateralParams: [
|
|
66
70
|
* {
|
|
67
71
|
* token: "0x0000000000000000000000000000000000007000",
|
|
68
72
|
* lltv: 770000000000000000n,
|
|
69
|
-
*
|
|
73
|
+
* liquidationCursor: 250000000000000000n,
|
|
70
74
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
71
75
|
* },
|
|
72
76
|
* ],
|
|
@@ -104,12 +108,14 @@ export declare class Group implements IGroup {
|
|
|
104
108
|
*
|
|
105
109
|
* const offer = Offer.create({
|
|
106
110
|
* market: {
|
|
111
|
+
* chainId: 8453,
|
|
112
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
107
113
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
108
114
|
* collateralParams: [
|
|
109
115
|
* {
|
|
110
116
|
* token: "0x0000000000000000000000000000000000007000",
|
|
111
117
|
* lltv: 770000000000000000n,
|
|
112
|
-
*
|
|
118
|
+
* liquidationCursor: 250000000000000000n,
|
|
113
119
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
114
120
|
* },
|
|
115
121
|
* ],
|
|
@@ -149,12 +155,14 @@ export declare class Group implements IGroup {
|
|
|
149
155
|
*
|
|
150
156
|
* const offer = Offer.create({
|
|
151
157
|
* market: {
|
|
158
|
+
* chainId: 8453,
|
|
159
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
152
160
|
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
153
161
|
* collateralParams: [
|
|
154
162
|
* {
|
|
155
163
|
* token: "0x0000000000000000000000000000000000007000",
|
|
156
164
|
* lltv: 770000000000000000n,
|
|
157
|
-
*
|
|
165
|
+
* liquidationCursor: 250000000000000000n,
|
|
158
166
|
* oracle: "0x0000000000000000000000000000000000008000",
|
|
159
167
|
* },
|
|
160
168
|
* ],
|