@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
@@ -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 { encode as encodePayload } from "./Payload.js";
9
- const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
10
- const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
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 with empty
110
- * `ratifierData`, then sends the temporary payload to the Midnight API
111
- * `POST /mempool/validate` endpoint. API policy only inspects offer contents,
112
- * so use this after `Tree.create` and before wallet signature or Setter root
113
- * approval.
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 before ratifier data or payload publication exists.
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
- * @returns API issues and `valid` summary.
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 {Payload.DecodeError} when validation payload encoding fails.
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
- * maxLif: 1061007957559681697n,
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
- * const validation = await TreeUtils.mempoolValidate({
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
- const offers = "offers" in params.tree
164
- ? params.tree.offers
165
- : params.tree.flatMap((entry) => "offers" in entry ? Group.from(entry).offers : [Offer.from(entry)]);
166
- buildDescriptor(offers);
167
- const payload = await encodePayload(offers.map((offer) => ({ offer, ratifierData: "0x" })));
168
- return MidnightApi.validateMempoolPayload({
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
- * maxLif: 1061007957559681697n,
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) => "offers" in entry
244
+ function buildDescriptor(entries, options = {}) {
245
+ const structs = entries.flatMap((entry) => GroupUtils.isGroupInput(entry)
248
246
  ? GroupUtils.toStructs(entry)
249
- : [OfferUtils.toStruct({ offer: entry })]);
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
- * maxLif: 1061007957559681697n,
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 contains the leaf.
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
- * maxLif: 1061007957559681697n,
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
- * maxLif: 1061007957559681697n,
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": "0.1.0",
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": "github:morpho-org/sdks",
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": "src/index.ts",
20
+ "main": "./lib/cjs/index.js",
18
21
  "exports": {
19
- ".": "./src/index.ts",
20
- "./api": "./src/api/index.ts",
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
- "src/api/index.ts"
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
- "peerDependencies": {
43
- "@morpho-org/morpho-ts": "^2.7.0",
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
+ }
@@ -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>;