@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.
Files changed (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -46
  3. package/lib/cjs/abis.d.ts +1185 -996
  4. package/lib/cjs/abis.js +1445 -1211
  5. package/lib/cjs/api/MidnightApi.d.ts +22 -16
  6. package/lib/cjs/api/MidnightApi.js +89 -19
  7. package/lib/cjs/api/helpers.d.ts +11 -1
  8. package/lib/cjs/api/helpers.js +54 -4
  9. package/lib/cjs/api/types.d.ts +35 -9
  10. package/lib/cjs/constants.d.ts +12 -11
  11. package/lib/cjs/constants.js +14 -12
  12. package/lib/cjs/errors.d.ts +89 -1
  13. package/lib/cjs/errors.js +114 -3
  14. package/lib/cjs/fetch/Market.js +37 -3
  15. package/lib/cjs/fetch/index.d.ts +0 -1
  16. package/lib/cjs/fetch/index.js +0 -1
  17. package/lib/cjs/fetch/utils.d.ts +1 -1
  18. package/lib/cjs/fetch/utils.js +9 -2
  19. package/lib/cjs/index.d.ts +1 -1
  20. package/lib/cjs/index.js +2 -23
  21. package/lib/cjs/market/Market.d.ts +99 -33
  22. package/lib/cjs/market/Market.js +137 -28
  23. package/lib/cjs/market/MarketUtils.d.ts +61 -41
  24. package/lib/cjs/market/MarketUtils.js +108 -48
  25. package/lib/cjs/market/Position.d.ts +16 -11
  26. package/lib/cjs/market/Position.js +18 -12
  27. package/lib/cjs/market/PositionUtils.d.ts +6 -4
  28. package/lib/cjs/market/PositionUtils.js +9 -6
  29. package/lib/cjs/math/TickLib.d.ts +22 -0
  30. package/lib/cjs/math/TickLib.js +30 -0
  31. package/lib/cjs/math/index.d.ts +0 -1
  32. package/lib/cjs/math/index.js +0 -1
  33. package/lib/cjs/offers/Offer.d.ts +218 -12
  34. package/lib/cjs/offers/Offer.js +215 -7
  35. package/lib/cjs/offers/OfferUtils.d.ts +249 -143
  36. package/lib/cjs/offers/OfferUtils.js +326 -45
  37. package/lib/cjs/queries/GetPosition.d.ts +1 -1
  38. package/lib/cjs/queries/GetPosition.js +1 -1
  39. package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +184 -38
  40. package/lib/cjs/signatures/EcrecoverRatifierUtils.js +296 -80
  41. package/lib/cjs/signatures/Group.d.ts +12 -4
  42. package/lib/cjs/signatures/Group.js +17 -7
  43. package/lib/cjs/signatures/GroupUtils.d.ts +60 -4
  44. package/lib/cjs/signatures/GroupUtils.js +57 -2
  45. package/lib/cjs/signatures/Payload.d.ts +277 -277
  46. package/lib/cjs/signatures/Payload.js +517 -534
  47. package/lib/cjs/signatures/RatifierUtils.d.ts +57 -0
  48. package/lib/cjs/signatures/RatifierUtils.js +105 -0
  49. package/lib/cjs/signatures/SetterRatifierUtils.d.ts +52 -13
  50. package/lib/cjs/signatures/SetterRatifierUtils.js +62 -19
  51. package/lib/cjs/signatures/Tree.d.ts +28 -16
  52. package/lib/cjs/signatures/Tree.js +35 -15
  53. package/lib/cjs/signatures/TreeUtils.d.ts +185 -63
  54. package/lib/cjs/signatures/TreeUtils.js +89 -79
  55. package/lib/cjs/signatures/eip712.d.ts +22 -0
  56. package/lib/cjs/signatures/eip712.js +26 -0
  57. package/lib/cjs/signatures/index.d.ts +2 -0
  58. package/lib/cjs/signatures/index.js +4 -0
  59. package/lib/cjs/signatures/offerStructInternal.d.ts +14 -0
  60. package/lib/cjs/signatures/offerStructInternal.js +72 -0
  61. package/lib/esm/abis.d.ts +1185 -996
  62. package/lib/esm/abis.js +1445 -1211
  63. package/lib/esm/api/MidnightApi.d.ts +22 -16
  64. package/lib/esm/api/MidnightApi.js +91 -21
  65. package/lib/esm/api/helpers.d.ts +11 -1
  66. package/lib/esm/api/helpers.js +54 -5
  67. package/lib/esm/api/types.d.ts +35 -9
  68. package/lib/esm/constants.d.ts +12 -11
  69. package/lib/esm/constants.js +13 -11
  70. package/lib/esm/errors.d.ts +89 -1
  71. package/lib/esm/errors.js +108 -2
  72. package/lib/esm/fetch/Market.js +38 -4
  73. package/lib/esm/fetch/index.d.ts +0 -1
  74. package/lib/esm/fetch/index.js +0 -1
  75. package/lib/esm/fetch/utils.d.ts +1 -1
  76. package/lib/esm/fetch/utils.js +9 -2
  77. package/lib/esm/index.d.ts +1 -1
  78. package/lib/esm/index.js +1 -1
  79. package/lib/esm/market/Market.d.ts +99 -33
  80. package/lib/esm/market/Market.js +137 -28
  81. package/lib/esm/market/MarketUtils.d.ts +61 -41
  82. package/lib/esm/market/MarketUtils.js +109 -49
  83. package/lib/esm/market/Position.d.ts +16 -11
  84. package/lib/esm/market/Position.js +19 -13
  85. package/lib/esm/market/PositionUtils.d.ts +6 -4
  86. package/lib/esm/market/PositionUtils.js +9 -6
  87. package/lib/esm/math/TickLib.d.ts +22 -0
  88. package/lib/esm/math/TickLib.js +31 -1
  89. package/lib/esm/math/index.d.ts +0 -1
  90. package/lib/esm/math/index.js +0 -1
  91. package/lib/esm/offers/Offer.d.ts +218 -12
  92. package/lib/esm/offers/Offer.js +216 -8
  93. package/lib/esm/offers/OfferUtils.d.ts +249 -143
  94. package/lib/esm/offers/OfferUtils.js +329 -48
  95. package/lib/esm/queries/GetPosition.d.ts +1 -1
  96. package/lib/esm/queries/GetPosition.js +1 -1
  97. package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +184 -38
  98. package/lib/esm/signatures/EcrecoverRatifierUtils.js +298 -82
  99. package/lib/esm/signatures/Group.d.ts +12 -4
  100. package/lib/esm/signatures/Group.js +17 -7
  101. package/lib/esm/signatures/GroupUtils.d.ts +60 -4
  102. package/lib/esm/signatures/GroupUtils.js +57 -2
  103. package/lib/esm/signatures/Payload.d.ts +277 -277
  104. package/lib/esm/signatures/Payload.js +517 -531
  105. package/lib/esm/signatures/RatifierUtils.d.ts +57 -0
  106. package/lib/esm/signatures/RatifierUtils.js +105 -0
  107. package/lib/esm/signatures/SetterRatifierUtils.d.ts +52 -13
  108. package/lib/esm/signatures/SetterRatifierUtils.js +62 -19
  109. package/lib/esm/signatures/Tree.d.ts +28 -16
  110. package/lib/esm/signatures/Tree.js +36 -16
  111. package/lib/esm/signatures/TreeUtils.d.ts +185 -63
  112. package/lib/esm/signatures/TreeUtils.js +91 -81
  113. package/lib/esm/signatures/eip712.d.ts +22 -0
  114. package/lib/esm/signatures/eip712.js +22 -0
  115. package/lib/esm/signatures/index.d.ts +2 -0
  116. package/lib/esm/signatures/index.js +2 -0
  117. package/lib/esm/signatures/offerStructInternal.d.ts +14 -0
  118. package/lib/esm/signatures/offerStructInternal.js +67 -0
  119. package/package.json +31 -34
  120. package/lib/cjs/fetch/Offer.d.ts +0 -74
  121. package/lib/cjs/fetch/Offer.js +0 -119
  122. package/lib/cjs/math/ConsumableUnitsLib.d.ts +0 -57
  123. package/lib/cjs/math/ConsumableUnitsLib.js +0 -77
  124. package/lib/esm/fetch/Offer.d.ts +0 -74
  125. package/lib/esm/fetch/Offer.js +0 -116
  126. package/lib/esm/math/ConsumableUnitsLib.d.ts +0 -57
  127. package/lib/esm/math/ConsumableUnitsLib.js +0 -74
  128. 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
- "0xc27c38e446b48c820ab9c4373dc63a4a750a08165cb4bb488206ebabe045d650",
11
- "0x4e15d8736f4406e07bf9844b1653474472a827130c61e899bf1f574a88b8d987",
12
- "0x46d107447b480c38ef5b7f54603dba0cb23b887f302b01a998b9d8a80320dd53",
13
- "0xd1f3607a8e81454bb3baf5f898274ab47541fffc690278a74f13e174e116be72",
14
- "0xb2d98adca9d116c9bc02ce59ec599ac3c2d33db1c0d1217c7e411d9198d427be",
15
- "0x5931e0597fcf986027f3118b2495a9ac22139d133f9ad2c2198e6738dc3886c5",
16
- "0x3967d37928614a085b47e8758fbc3869a8aed63bdf60ccee8536ff2b5064da06",
17
- "0xd6b9f5f45915a260f6e521d9b40f86c385730b6bc330590fcde212e2fea64263",
18
- "0x080caa519dbd5328c119d9907e0fa3d9a50dc2ae4bf6dd42c93c100dbc89b51a",
19
- "0x45da471048924165ea2ad1855ba940e454b486e71dcf1666c71a928c8844c419",
20
- "0xa49a9434fc1836bd08097368325b31039b6a0fd44919f53e4d8f4bf814084cb0",
21
- "0xd3e93e4525132f0187a6964dc01fef33fde414538ffd212e9f2f478c3263e0a0",
22
- "0x25990db2d26547f92c711988300df317af57bad5cd5d9d8e787a82f95c929474",
23
- "0x8e0c648afa977572ead40a1d10a6db2c425b8099545006d834a7b849c6166643",
24
- "0x4b635250efa6243e277fdd0cf6df993c2943b64f10f3a0756ceb1f47ef8f9b18",
25
- "0xbde1c927f6222c07c8df264e68b42b8382c7c2b85f4729e0df94297cfeebfa91",
26
- "0x4d58aea1a67f94be21ab1415bf3b602592430eb9112268fd0fc4e141b1a35e76",
27
- "0x14c03281bce13010b158e5a4a3378be394ac9e16118aedb17d82ced51e66836c",
28
- "0x99fd3e76f43b2cc221cb9860bc6c96cda95af3fa07ef5f04e071b54aa9386d06",
29
- "0x1b1c2f1a04968094d8d0453d49838f7a809d1202ae04a1c2e0964e442ff7988b",
30
- "0xc8ccd3cb3267dd76f563584920ac60f2283b719917481b85fe5e10b754932455",
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: "maxLif", type: "uint256" },
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: "uint256" },
87
- { name: "maxAssets", type: "uint256" },
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
- const getTreeRatifier = (tree) => {
101
- const offers = tree.offers;
102
- const firstOffer = offers[0];
103
- if (firstOffer == null) {
104
- throw new errors_js_1.InvalidTreeError("Tree must contain at least one offer.");
105
- }
106
- const ratifier = firstOffer.ratifier;
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
- * maxLif: 1061007957559681697n,
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 = getTreeRatifier(params.tree);
206
- const treeType = params.tree.height === 0
207
- ? "Offer"
208
- : `Offer${"[2]".repeat(params.tree.height)}`;
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(params.tree.paddedOffers),
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
- * maxLif: 1061007957559681697n,
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 = getTreeRatifier(params.tree);
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(params.tree.height),
279
- params.tree.root,
288
+ treeTypeHash(tree.height),
289
+ tree.root,
280
290
  ]));
281
- return (0, viem_1.keccak256)((0, viem_1.concat)(["0x1901", domainSeparator, structHash]));
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 contains multiple ratifiers.
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
- * maxLif: 1061007957559681697n,
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: params.tree,
348
- chainId: params.client.chain.id,
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
- const isValidSignature = await (0, viem_1.verifyTypedData)({
355
- ...data,
356
- address: signer,
357
- signature,
358
- });
359
- if (!isValidSignature)
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: signature.v != null
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: Number(parsed.v ?? BigInt(parsed.yParity + 27)),
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
- * maxLif: 1061007957559681697n,
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
- getTreeRatifier(params.tree);
528
- const proof = params.tree.proof(params.leafIndex);
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 returns a signature that does not recover to `params.account`.
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
- * maxLif: 1061007957559681697n,
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(params));
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 params.tree.offers) {
821
+ for (const offer of tree.offers) {
606
822
  items.push({
607
823
  offer,
608
824
  ratifierData: ratifierData({
609
- tree: params.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
- * maxLif: 1061007957559681697n,
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
- * maxLif: 1061007957559681697n,
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
- * maxLif: 1061007957559681697n,
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
- * maxLif: 1061007957559681697n,
165
+ * liquidationCursor: 250000000000000000n,
158
166
  * oracle: "0x0000000000000000000000000000000000008000",
159
167
  * },
160
168
  * ],