@morpho-org/midnight-sdk 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) 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 +22 -16
  7. package/lib/cjs/api/helpers.js +6 -3
  8. package/lib/cjs/api/types.d.ts +35 -9
  9. package/lib/cjs/constants.d.ts +12 -11
  10. package/lib/cjs/constants.js +14 -12
  11. package/lib/cjs/errors.d.ts +74 -1
  12. package/lib/cjs/errors.js +94 -3
  13. package/lib/cjs/fetch/Market.js +0 -1
  14. package/lib/cjs/fetch/index.d.ts +0 -1
  15. package/lib/cjs/fetch/index.js +0 -1
  16. package/lib/cjs/index.d.ts +1 -1
  17. package/lib/cjs/index.js +2 -23
  18. package/lib/cjs/market/Market.d.ts +99 -33
  19. package/lib/cjs/market/Market.js +137 -28
  20. package/lib/cjs/market/MarketUtils.d.ts +61 -41
  21. package/lib/cjs/market/MarketUtils.js +108 -48
  22. package/lib/cjs/market/Position.d.ts +16 -11
  23. package/lib/cjs/market/Position.js +18 -12
  24. package/lib/cjs/market/PositionUtils.d.ts +6 -4
  25. package/lib/cjs/market/PositionUtils.js +9 -6
  26. package/lib/cjs/math/TickLib.d.ts +22 -0
  27. package/lib/cjs/math/TickLib.js +30 -0
  28. package/lib/cjs/math/index.d.ts +0 -1
  29. package/lib/cjs/math/index.js +0 -1
  30. package/lib/cjs/offers/Offer.d.ts +217 -11
  31. package/lib/cjs/offers/Offer.js +215 -7
  32. package/lib/cjs/offers/OfferUtils.d.ts +245 -139
  33. package/lib/cjs/offers/OfferUtils.js +304 -36
  34. package/lib/cjs/queries/GetPosition.d.ts +1 -1
  35. package/lib/cjs/queries/GetPosition.js +1 -1
  36. package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +66 -38
  37. package/lib/cjs/signatures/EcrecoverRatifierUtils.js +147 -79
  38. package/lib/cjs/signatures/Group.d.ts +12 -4
  39. package/lib/cjs/signatures/Group.js +12 -4
  40. package/lib/cjs/signatures/GroupUtils.d.ts +12 -4
  41. package/lib/cjs/signatures/GroupUtils.js +6 -2
  42. package/lib/cjs/signatures/Payload.d.ts +277 -277
  43. package/lib/cjs/signatures/Payload.js +517 -534
  44. package/lib/cjs/signatures/RatifierUtils.d.ts +57 -0
  45. package/lib/cjs/signatures/RatifierUtils.js +94 -0
  46. package/lib/cjs/signatures/SetterRatifierUtils.d.ts +21 -13
  47. package/lib/cjs/signatures/SetterRatifierUtils.js +25 -20
  48. package/lib/cjs/signatures/Tree.d.ts +28 -16
  49. package/lib/cjs/signatures/Tree.js +25 -13
  50. package/lib/cjs/signatures/TreeUtils.d.ts +181 -62
  51. package/lib/cjs/signatures/TreeUtils.js +73 -76
  52. package/lib/cjs/signatures/index.d.ts +1 -0
  53. package/lib/cjs/signatures/index.js +3 -0
  54. package/lib/cjs/signatures/offerStructInternal.d.ts +14 -0
  55. package/lib/cjs/signatures/offerStructInternal.js +72 -0
  56. package/lib/esm/abis.d.ts +1185 -996
  57. package/lib/esm/abis.js +1445 -1211
  58. package/lib/esm/api/MidnightApi.d.ts +22 -16
  59. package/lib/esm/api/MidnightApi.js +23 -17
  60. package/lib/esm/api/helpers.js +6 -3
  61. package/lib/esm/api/types.d.ts +35 -9
  62. package/lib/esm/constants.d.ts +12 -11
  63. package/lib/esm/constants.js +13 -11
  64. package/lib/esm/errors.d.ts +74 -1
  65. package/lib/esm/errors.js +89 -2
  66. package/lib/esm/fetch/Market.js +0 -1
  67. package/lib/esm/fetch/index.d.ts +0 -1
  68. package/lib/esm/fetch/index.js +0 -1
  69. package/lib/esm/index.d.ts +1 -1
  70. package/lib/esm/index.js +1 -1
  71. package/lib/esm/market/Market.d.ts +99 -33
  72. package/lib/esm/market/Market.js +137 -28
  73. package/lib/esm/market/MarketUtils.d.ts +61 -41
  74. package/lib/esm/market/MarketUtils.js +109 -49
  75. package/lib/esm/market/Position.d.ts +16 -11
  76. package/lib/esm/market/Position.js +19 -13
  77. package/lib/esm/market/PositionUtils.d.ts +6 -4
  78. package/lib/esm/market/PositionUtils.js +9 -6
  79. package/lib/esm/math/TickLib.d.ts +22 -0
  80. package/lib/esm/math/TickLib.js +31 -1
  81. package/lib/esm/math/index.d.ts +0 -1
  82. package/lib/esm/math/index.js +0 -1
  83. package/lib/esm/offers/Offer.d.ts +217 -11
  84. package/lib/esm/offers/Offer.js +216 -8
  85. package/lib/esm/offers/OfferUtils.d.ts +245 -139
  86. package/lib/esm/offers/OfferUtils.js +306 -38
  87. package/lib/esm/queries/GetPosition.d.ts +1 -1
  88. package/lib/esm/queries/GetPosition.js +1 -1
  89. package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +66 -38
  90. package/lib/esm/signatures/EcrecoverRatifierUtils.js +149 -81
  91. package/lib/esm/signatures/Group.d.ts +12 -4
  92. package/lib/esm/signatures/Group.js +12 -4
  93. package/lib/esm/signatures/GroupUtils.d.ts +12 -4
  94. package/lib/esm/signatures/GroupUtils.js +6 -2
  95. package/lib/esm/signatures/Payload.d.ts +277 -277
  96. package/lib/esm/signatures/Payload.js +517 -531
  97. package/lib/esm/signatures/RatifierUtils.d.ts +57 -0
  98. package/lib/esm/signatures/RatifierUtils.js +94 -0
  99. package/lib/esm/signatures/SetterRatifierUtils.d.ts +21 -13
  100. package/lib/esm/signatures/SetterRatifierUtils.js +25 -20
  101. package/lib/esm/signatures/Tree.d.ts +28 -16
  102. package/lib/esm/signatures/Tree.js +25 -13
  103. package/lib/esm/signatures/TreeUtils.d.ts +181 -62
  104. package/lib/esm/signatures/TreeUtils.js +75 -78
  105. package/lib/esm/signatures/index.d.ts +1 -0
  106. package/lib/esm/signatures/index.js +1 -0
  107. package/lib/esm/signatures/offerStructInternal.d.ts +14 -0
  108. package/lib/esm/signatures/offerStructInternal.js +67 -0
  109. package/package.json +28 -32
  110. package/src/index.ts +1 -1
  111. package/lib/cjs/fetch/Offer.d.ts +0 -74
  112. package/lib/cjs/fetch/Offer.js +0 -119
  113. package/lib/cjs/math/ConsumableUnitsLib.d.ts +0 -57
  114. package/lib/cjs/math/ConsumableUnitsLib.js +0 -77
  115. package/lib/esm/fetch/Offer.d.ts +0 -74
  116. package/lib/esm/fetch/Offer.js +0 -116
  117. package/lib/esm/math/ConsumableUnitsLib.d.ts +0 -57
  118. package/lib/esm/math/ConsumableUnitsLib.js +0 -74
@@ -1,61 +1,14 @@
1
1
  import { deepFreeze } from "@morpho-org/morpho-ts";
2
- import { concat, keccak256 } from "viem";
2
+ import { concat, keccak256, } from "viem";
3
3
  import { MidnightApi } from "../api/MidnightApi.js";
4
- import { InvalidTreeError, InvalidTreeHeightError } from "../errors.js";
4
+ import { InvalidTreeError, InvalidTreeHeightError, MidnightMempoolValidationError, } from "../errors.js";
5
5
  import { Offer, OfferUtils, } from "../offers/index.js";
6
+ import { EcrecoverRatifierUtils, } from "./EcrecoverRatifierUtils.js";
6
7
  import { Group } from "./Group.js";
7
8
  import { GroupUtils } from "./GroupUtils.js";
8
- import { 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,49 @@ 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) => "offers" in entry
124
+ ? Group.from(entry).offers
125
+ : [Offer.from(entry)]);
126
+ if (!("paddedOffers" in params.tree)) {
127
+ buildDescriptor(params.tree);
128
+ }
129
+ items = offers.map((offer) => ({
130
+ offer,
131
+ ratifierData: "0x",
132
+ }));
133
+ }
134
+ else if (params.ratification.type === "ecrecover") {
135
+ if (params.ratification.signature != null) {
136
+ items = await EcrecoverRatifierUtils.ratify({
137
+ tree: params.tree,
138
+ signature: params.ratification.signature,
139
+ account: params.ratification.account,
140
+ });
141
+ }
142
+ else {
143
+ items = await EcrecoverRatifierUtils.ratify({
144
+ tree: params.tree,
145
+ client: params.ratification.client,
146
+ account: params.ratification.account,
147
+ });
148
+ }
149
+ }
150
+ else {
151
+ items = SetterRatifierUtils.ratify({ tree: params.tree });
152
+ }
153
+ const payload = await Payload.encode(items);
154
+ const validation = await MidnightApi.validateMempoolPayload({
169
155
  baseUrl: params.apiUrl,
170
156
  fetch: params.fetch,
171
157
  request: params.request,
@@ -173,6 +159,10 @@ export var TreeUtils;
173
159
  timestamp: params.timestamp,
174
160
  payload,
175
161
  });
162
+ if (!validation.valid) {
163
+ throw new MidnightMempoolValidationError(validation.issues);
164
+ }
165
+ return { valid: true, issues: validation.issues };
176
166
  }
177
167
  TreeUtils.mempoolValidate = mempoolValidate;
178
168
  /**
@@ -218,12 +208,14 @@ export var TreeUtils;
218
208
  *
219
209
  * const offer = Offer.create({
220
210
  * market: {
211
+ * chainId: 8453,
212
+ * midnight: "0x0000000000000000000000000000000000001000",
221
213
  * loanToken: "0x0000000000000000000000000000000000006000",
222
214
  * collateralParams: [
223
215
  * {
224
216
  * token: "0x0000000000000000000000000000000000007000",
225
217
  * lltv: 770000000000000000n,
226
- * maxLif: 1061007957559681697n,
218
+ * liquidationCursor: 250000000000000000n,
227
219
  * oracle: "0x0000000000000000000000000000000000008000",
228
220
  * },
229
221
  * ],
@@ -290,12 +282,14 @@ export var TreeUtils;
290
282
  *
291
283
  * const offer = Offer.create({
292
284
  * market: {
285
+ * chainId: 8453,
286
+ * midnight: "0x0000000000000000000000000000000000001000",
293
287
  * loanToken: "0x0000000000000000000000000000000000006000",
294
288
  * collateralParams: [
295
289
  * {
296
290
  * token: "0x0000000000000000000000000000000000007000",
297
291
  * lltv: 770000000000000000n,
298
- * maxLif: 1061007957559681697n,
292
+ * liquidationCursor: 250000000000000000n,
299
293
  * oracle: "0x0000000000000000000000000000000000008000",
300
294
  * },
301
295
  * ],
@@ -326,7 +320,7 @@ export var TreeUtils;
326
320
  * built-in Ecrecover and Setter helpers call this while generating
327
321
  * `ratifierData`.
328
322
  *
329
- * @param params.tree - Tree that contains the leaf.
323
+ * @param params.tree - Tree-like data with the root and leaves that contain the leaf.
330
324
  * @param params.leafIndex - Leaf index to prove.
331
325
  * @returns Proof descriptor.
332
326
  * @throws {InvalidTreeError} when leaf index is out of range.
@@ -337,12 +331,14 @@ export var TreeUtils;
337
331
  *
338
332
  * const offer = Offer.create({
339
333
  * market: {
334
+ * chainId: 8453,
335
+ * midnight: "0x0000000000000000000000000000000000001000",
340
336
  * loanToken: "0x0000000000000000000000000000000000006000",
341
337
  * collateralParams: [
342
338
  * {
343
339
  * token: "0x0000000000000000000000000000000000007000",
344
340
  * lltv: 770000000000000000n,
345
- * maxLif: 1061007957559681697n,
341
+ * liquidationCursor: 250000000000000000n,
346
342
  * oracle: "0x0000000000000000000000000000000000008000",
347
343
  * },
348
344
  * ],
@@ -367,8 +363,7 @@ export var TreeUtils;
367
363
  */
368
364
  function buildProof(params) {
369
365
  const leafIndex = BigInt(params.leafIndex);
370
- if (leafIndex < 0n ||
371
- leafIndex >= BigInt(params.tree.paddedOffers.length)) {
366
+ if (leafIndex < 0n || leafIndex >= BigInt(params.tree.leaves.length)) {
372
367
  throw new InvalidTreeError(`Leaf index "${leafIndex}" is outside the tree.`);
373
368
  }
374
369
  let index = Number(leafIndex);
@@ -405,12 +400,14 @@ export var TreeUtils;
405
400
  *
406
401
  * const offer = Offer.create({
407
402
  * market: {
403
+ * chainId: 8453,
404
+ * midnight: "0x0000000000000000000000000000000000001000",
408
405
  * loanToken: "0x0000000000000000000000000000000000006000",
409
406
  * collateralParams: [
410
407
  * {
411
408
  * token: "0x0000000000000000000000000000000000007000",
412
409
  * lltv: 770000000000000000n,
413
- * maxLif: 1061007957559681697n,
410
+ * liquidationCursor: 250000000000000000n,
414
411
  * oracle: "0x0000000000000000000000000000000000008000",
415
412
  * },
416
413
  * ],
@@ -1,6 +1,7 @@
1
1
  export * from "./EcrecoverRatifierUtils.js";
2
2
  export * from "./Group.js";
3
3
  export * from "./GroupUtils.js";
4
+ export { Payload } from "./Payload.js";
4
5
  export * from "./RatifierUtils.js";
5
6
  export * from "./SetterRatifierUtils.js";
6
7
  export * from "./Tree.js";
@@ -1,6 +1,7 @@
1
1
  export * from "./EcrecoverRatifierUtils.js";
2
2
  export * from "./Group.js";
3
3
  export * from "./GroupUtils.js";
4
+ export { Payload } from "./Payload.js";
4
5
  export * from "./RatifierUtils.js";
5
6
  export * from "./SetterRatifierUtils.js";
6
7
  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.0.0",
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",
@@ -16,8 +19,16 @@
16
19
  "type": "module",
17
20
  "main": "src/index.ts",
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": {
@@ -31,39 +42,24 @@
31
42
  "files": [
32
43
  "lib"
33
44
  ],
34
- "scripts": {
35
- "prepublish": "$npm_execpath build",
36
- "compile": "node ../../scripts/compile-solidity.js midnight-sdk",
37
- "build": "tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
38
- "build:cjs": "tsc --build tsconfig.build.cjs.json && echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json",
39
- "build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
40
- "test": "vitest --root ../.. --project midnight-sdk"
41
- },
42
45
  "peerDependencies": {
43
46
  "@morpho-org/morpho-ts": "^2.7.0",
44
47
  "viem": "^2.0.0"
45
48
  },
46
49
  "devDependencies": {
47
- "@morpho-org/morpho-ts": "workspace:^",
48
- "@morpho-org/test": "workspace:^",
49
- "fast-check": "^4.4.0",
50
+ "fast-check": "^4.8.0",
50
51
  "typescript": "^6.0.3",
51
- "viem": "2.52.2",
52
- "vitest": "^4.1.6"
52
+ "viem": "^2.54.2",
53
+ "vitest": "^4.1.9",
54
+ "@morpho-org/morpho-ts": "^2.7.0",
55
+ "@morpho-org/test": "^2.8.1"
53
56
  },
54
- "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
- }
57
+ "scripts": {
58
+ "prepublish": "$npm_execpath build",
59
+ "compile": "node ../../scripts/compile-solidity.js midnight-sdk",
60
+ "build": "tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
61
+ "build:cjs": "tsc --build tsconfig.build.cjs.json && echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json",
62
+ "build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
63
+ "test": "vitest --root ../.. --project midnight-sdk"
68
64
  }
69
- }
65
+ }
package/src/index.ts CHANGED
@@ -16,4 +16,4 @@ export * from "./signatures/index.js";
16
16
  * Encoded payloads are always `Hex` strings ready to be included in onchain
17
17
  * mempool submission calldata.
18
18
  */
19
- export * as Payload from "./signatures/Payload.js";
19
+ export { Payload } from "./signatures/Payload.js";
@@ -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>;
@@ -1,119 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchConsumableUnits = fetchConsumableUnits;
4
- const morpho_ts_1 = require("@morpho-org/morpho-ts");
5
- const actions_1 = require("viem/actions");
6
- const abis_js_1 = require("../abis.js");
7
- const index_js_1 = require("../math/index.js");
8
- const index_js_2 = require("../offers/index.js");
9
- const utils_js_1 = require("./utils.js");
10
- /**
11
- * Fetches and computes remaining consumable units for an offer.
12
- *
13
- * Unit-capped offers skip settlement-fee lookup, matching the Solidity
14
- * library's early return. For asset-capped offers, pass the time to maturity
15
- * for the same block context as the quote.
16
- *
17
- * Reads `eth_chainId` only when the viem client has no configured chain id,
18
- * then reads `Midnight.consumed(offer.maker, group)` and
19
- * `Midnight.continuousFee(marketId)`. If the offer's continuous fee cap is
20
- * below the market's current continuous fee, returns zero. For asset-capped
21
- * offers where `offer.maxUnits` is zero, also reads
22
- * `Midnight.settlementFee(marketId, timeToMaturity)`.
23
- *
24
- * @param client - Viem client used for the reads.
25
- * @param params.marketId - Market id used for settlement-fee lookup on asset-capped offers.
26
- * @param params.offer.buy - Whether the maker buys loan assets.
27
- * @param params.offer.maker - Maker address whose consumed group amount is read.
28
- * @param params.offer.tick - Offer tick used for asset-to-unit conversion.
29
- * @param params.offer.maxUnits - Unit cap; when non-zero, settlement-fee lookup is skipped.
30
- * @param params.offer.maxAssets - Asset cap used when `params.offer.maxUnits` is zero.
31
- * @param params.offer.continuousFeeCap - Maximum market continuous fee accepted by this offer.
32
- * @param params.group - Offer group id whose consumed amount is read.
33
- * @param params.timeToMaturity - Time to maturity used for settlement-fee lookup on asset-capped offers.
34
- * @param params.account - Optional account used as the `from` field for the reads.
35
- * @param params.blockNumber - Optional block number used for the reads.
36
- * @param params.blockTag - Optional block tag used for the reads.
37
- * @param params.stateOverride - Optional state override set used for the reads.
38
- * @returns Consumable units.
39
- * @throws {UnsupportedChainIdError} when no address registry exists for the client chain id.
40
- * @throws {UnknownAddressError} when the registry has no Midnight address for the client chain id.
41
- * @throws {NegativeValueError} when asset-capped `timeToMaturity`, offer caps, or SDK math inputs are negative.
42
- * @throws {InvalidOfferParameterError} when offer caps are both zero or both non-zero.
43
- * @throws {DivisionByZeroError} when the delegated units conversion divides by zero.
44
- * @throws {SettlementFeeExceedsPriceError} when settlement fee exceeds a buy offer price.
45
- * @example
46
- * ```ts
47
- * import { fetchConsumableUnits } from "@morpho-org/midnight-sdk";
48
- * import { createPublicClient, http, zeroHash } from "viem";
49
- * import { base } from "viem/chains";
50
- *
51
- * const client = createPublicClient({ chain: base, transport: http() });
52
- * const units = await fetchConsumableUnits(client, {
53
- * marketId: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
54
- * offer: {
55
- * buy: true,
56
- * maker: "0x0000000000000000000000000000000000009000",
57
- * tick: 5_000n,
58
- * maxUnits: 100n,
59
- * maxAssets: 0n,
60
- * continuousFeeCap: 317097919n,
61
- * },
62
- * group: zeroHash,
63
- * timeToMaturity: 3_600n,
64
- * });
65
- * console.log(units);
66
- * ```
67
- */
68
- async function fetchConsumableUnits(client, params) {
69
- const maxUnits = BigInt(params.offer.maxUnits);
70
- const maxAssets = BigInt(params.offer.maxAssets);
71
- const continuousFeeCap = BigInt(params.offer.continuousFeeCap);
72
- (0, morpho_ts_1.assertNonNegative)("offer.maxUnits", maxUnits);
73
- (0, morpho_ts_1.assertNonNegative)("offer.maxAssets", maxAssets);
74
- (0, morpho_ts_1.assertNonNegative)("offer.continuousFeeCap", continuousFeeCap);
75
- index_js_2.OfferUtils.validateOfferCaps({ maxUnits, maxAssets });
76
- const needsSettlementFee = maxUnits === 0n;
77
- const timeToMaturity = needsSettlementFee
78
- ? BigInt(params.timeToMaturity)
79
- : 0n;
80
- if (needsSettlementFee) {
81
- (0, morpho_ts_1.assertNonNegative)("timeToMaturity", timeToMaturity);
82
- }
83
- const chainId = await (0, utils_js_1.resolveChainId)(client);
84
- const midnight = (0, morpho_ts_1.getChainAddress)(chainId, "midnight");
85
- const consumed = (0, actions_1.readContract)(client, {
86
- ...(0, utils_js_1.callParameters)(params),
87
- address: midnight,
88
- abi: abis_js_1.midnightAbi,
89
- functionName: "consumed",
90
- args: [params.offer.maker, params.group],
91
- });
92
- const continuousFee = (0, actions_1.readContract)(client, {
93
- ...(0, utils_js_1.callParameters)(params),
94
- address: midnight,
95
- abi: abis_js_1.midnightAbi,
96
- functionName: "continuousFee",
97
- args: [params.marketId],
98
- });
99
- const [consumedValue, marketContinuousFee] = await Promise.all([
100
- consumed,
101
- continuousFee,
102
- ]);
103
- if (continuousFeeCap < BigInt(marketContinuousFee))
104
- return 0n;
105
- const settlementFee = needsSettlementFee
106
- ? await (0, actions_1.readContract)(client, {
107
- ...(0, utils_js_1.callParameters)(params),
108
- address: midnight,
109
- abi: abis_js_1.midnightAbi,
110
- functionName: "settlementFee",
111
- args: [params.marketId, timeToMaturity],
112
- })
113
- : 0n;
114
- return index_js_1.ConsumableUnitsLib.consumableUnits({
115
- offer: params.offer,
116
- consumed: consumedValue,
117
- settlementFee,
118
- });
119
- }