@morpho-org/midnight-sdk 1.2.0 → 1.3.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.
@@ -1,5 +1,6 @@
1
1
  import type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationResult, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiConstructorConfig, MidnightApiQuoteResult, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams } from "./types.js";
2
- export type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationIssue, MempoolPayloadValidationResult, MempoolPayloadValidationSuccess, MidnightApiBookMarket, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBookSide, MidnightApiBookSort, MidnightApiBookSortField, MidnightApiBookSortTerm, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiCollateral, MidnightApiConfig, MidnightApiConstructorConfig, MidnightApiFetch, MidnightApiPriceLevel, MidnightApiQuote, MidnightApiQuoteAssetsTarget, MidnightApiQuoteAverageWorstPriceGuard, MidnightApiQuoteResult, MidnightApiQuoteSlippageGuard, MidnightApiQuoteUnitsTarget, MidnightApiQuoteWithoutGuard, MidnightApiRequestOptions, MidnightApiSlippage, MidnightApiTake, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams, } from "./types.js";
2
+ export type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationIssue, MempoolPayloadValidationIssueDetails, MempoolPayloadValidationResult, MempoolPayloadValidationSuccess, MidnightApiBookMarket, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBookSide, MidnightApiBookSort, MidnightApiBookSortField, MidnightApiBookSortTerm, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiCollateral, MidnightApiConfig, MidnightApiConstructorConfig, MidnightApiFetch, MidnightApiPriceLevel, MidnightApiQuote, MidnightApiQuoteAssetsTarget, MidnightApiQuoteAverageWorstPriceGuard, MidnightApiQuoteResult, MidnightApiQuoteSlippageGuard, MidnightApiQuoteUnitsTarget, MidnightApiQuoteWithoutGuard, MidnightApiRequestOptions, MidnightApiSlippage, MidnightApiTake, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams, } from "./types.js";
3
+ export { MempoolPayloadValidationRule } from "./types.js";
3
4
  /**
4
5
  * Midnight API client and stateless helper surface for books and mempool data.
5
6
  *
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MidnightApi = void 0;
3
+ exports.MidnightApi = exports.MempoolPayloadValidationRule = void 0;
4
4
  const morpho_ts_1 = require("@morpho-org/morpho-ts");
5
5
  const errors_js_1 = require("../errors.js");
6
6
  const index_js_1 = require("../math/index.js");
7
7
  const Payload_js_1 = require("../signatures/Payload.js");
8
8
  const helpers_js_1 = require("./helpers.js");
9
+ var types_js_1 = require("./types.js");
10
+ Object.defineProperty(exports, "MempoolPayloadValidationRule", { enumerable: true, get: function () { return types_js_1.MempoolPayloadValidationRule; } });
9
11
  /**
10
12
  * Midnight API client and stateless helper surface for books and mempool data.
11
13
  *
@@ -1,5 +1,5 @@
1
1
  import { type Address, type Hash } from "viem";
2
- import type { ApiBookMarketResponse, ApiCollateralResponse, ApiPriceLevelResponse, ApiRequestParams, ApiTakeableOfferResponse, MempoolPayloadValidationResult, MidnightApiBookMarket, MidnightApiBookSide, MidnightApiCollateral, MidnightApiPriceLevel, MidnightApiTake } from "./types.js";
2
+ import { type ApiBookMarketResponse, type ApiCollateralResponse, type ApiPriceLevelResponse, type ApiRequestParams, type ApiTakeableOfferResponse, type MempoolPayloadValidationResult, type MidnightApiBookMarket, type MidnightApiBookSide, type MidnightApiCollateral, type MidnightApiPriceLevel, type MidnightApiTake } from "./types.js";
3
3
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
4
4
  export declare function requestMidnightApi<Response = unknown>(params: ApiRequestParams): Promise<Response>;
5
5
  /** @internal Builds a book endpoint path with encoded path segments. */
@@ -12,10 +12,10 @@ const morpho_ts_1 = require("@morpho-org/morpho-ts");
12
12
  const viem_1 = require("viem");
13
13
  const errors_js_1 = require("../errors.js");
14
14
  const index_js_1 = require("../market/index.js");
15
+ const types_js_1 = require("./types.js");
16
+ const version_generated_js_1 = require("./version.generated.js");
15
17
  const DEFAULT_MIDNIGHT_API_URL = new URL("/v0/midnight", morpho_ts_1.BLUE_API_BASE_URL);
16
- // Keep this literal in source so the browser ESM build does not import package.json
17
- // through Node-only createRequire/module shims.
18
- const MIDNIGHT_SDK_VERSION = "1.0.1";
18
+ const MAX_UINT256_DECIMAL_LENGTH = viem_1.maxUint256.toString().length;
19
19
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
20
20
  async function requestMidnightApi(params) {
21
21
  const baseUrl = new URL(params.baseUrl ?? DEFAULT_MIDNIGHT_API_URL);
@@ -46,7 +46,7 @@ async function requestMidnightApi(params) {
46
46
  const headers = new Headers(params.request?.headers);
47
47
  if (params.body !== undefined)
48
48
  headers.set("Content-Type", "application/json");
49
- headers.set("sdk-version", MIDNIGHT_SDK_VERSION);
49
+ headers.set("sdk-version", version_generated_js_1.MIDNIGHT_SDK_VERSION);
50
50
  const init = {
51
51
  ...params.request,
52
52
  method: params.method,
@@ -222,7 +222,38 @@ function parseValidationResponse(response) {
222
222
  if (typeof rule !== "string") {
223
223
  throw new errors_js_1.InvalidMidnightApiResponseError('Midnight API validation issue is missing "rule".');
224
224
  }
225
- return { rule };
225
+ const details = record.details;
226
+ if (details == null)
227
+ return { rule };
228
+ if (rule === types_js_1.MempoolPayloadValidationRule.MinOfferAssetsUsd &&
229
+ isRecord(details)) {
230
+ const loanToken = details.loan_token;
231
+ const rawMinAssets = details.min_assets;
232
+ if (typeof loanToken === "string" &&
233
+ (0, viem_1.isAddress)(loanToken) &&
234
+ typeof rawMinAssets === "string" &&
235
+ rawMinAssets.length <= MAX_UINT256_DECIMAL_LENGTH &&
236
+ /^\d+$/.test(rawMinAssets)) {
237
+ const minAssets = BigInt(rawMinAssets);
238
+ if (minAssets <= viem_1.maxUint256) {
239
+ return {
240
+ rule,
241
+ details: {
242
+ type: "minOfferAssetsUsd",
243
+ loanToken,
244
+ minAssets,
245
+ },
246
+ };
247
+ }
248
+ }
249
+ }
250
+ return {
251
+ rule,
252
+ details: {
253
+ type: "unknown",
254
+ raw: details,
255
+ },
256
+ };
226
257
  });
227
258
  return {
228
259
  valid: issues.length === 0,
@@ -194,11 +194,79 @@ export interface FetchTakeableOffersParams extends MidnightApiConfig {
194
194
  readonly cursor?: string;
195
195
  }
196
196
  /**
197
- * One API validation issue.
197
+ * `MempoolPayloadValidationRule` lists known Midnight mempool validation rules.
198
+ */
199
+ export declare const MempoolPayloadValidationRule: {
200
+ readonly MinOfferAssetsUsd: "min_offer_assets_usd";
201
+ readonly PayloadVersion: "payload_version";
202
+ readonly PayloadFrame: "payload_frame";
203
+ readonly PayloadGzipLength: "payload_gzip_length";
204
+ readonly PayloadSuffixTooLarge: "payload_suffix_too_large";
205
+ readonly PayloadDecompression: "payload_decompression";
206
+ readonly PayloadAbiDecode: "payload_abi_decode";
207
+ readonly EmptyPayload: "empty_payload";
208
+ readonly MaxOffersPerTree: "max_offers_per_tree";
209
+ readonly DuplicateOfferHash: "duplicate_offer_hash";
210
+ readonly UnsupportedChain: "unsupported_chain";
211
+ readonly MarketChainMismatch: "market_chain_mismatch";
212
+ readonly Maturity: "maturity";
213
+ readonly LoanToken: "loan_token";
214
+ readonly CollateralToken: "collateral_token";
215
+ readonly Oracle: "oracle";
216
+ readonly MarketTriplet: "market_triplet";
217
+ readonly RcfThreshold: "rcf_threshold";
218
+ readonly CollateralLltv: "collateral_lltv";
219
+ readonly MaxLif: "max_lif";
220
+ readonly MaxCollaterals: "max_collaterals";
221
+ readonly AmountMissing: "amount_missing";
222
+ readonly AmountConflict: "amount_conflict";
223
+ readonly MinTick: "min_tick";
224
+ readonly MaxTick: "max_tick";
225
+ readonly TickSpacing: "tick_spacing";
226
+ readonly MinDuration: "min_duration";
227
+ readonly Ratifier: "ratifier";
228
+ readonly MixedMaker: "mixed_maker";
229
+ readonly MixedRatifier: "mixed_ratifier";
230
+ readonly GroupIdentity: "group_identity";
231
+ readonly GroupConsistency: "group_consistency";
232
+ readonly NonEmptyCallback: "non_empty_callback";
233
+ readonly BuyEmptyCallback: "buy_empty_callback";
234
+ readonly SellEmptyCallback: "sell_empty_callback";
235
+ };
236
+ /**
237
+ * `MempoolPayloadValidationRule` represents a rule returned by the API.
238
+ *
239
+ * Known values have autocomplete through the matching constant; the open
240
+ * string branch keeps newer API rules forward-compatible.
241
+ */
242
+ export type MempoolPayloadValidationRule = (typeof MempoolPayloadValidationRule)[keyof typeof MempoolPayloadValidationRule] | (string & Record<never, never>);
243
+ /**
244
+ * `MempoolPayloadValidationIssueDetails` represents parsed issue details.
245
+ *
246
+ * Unrecognized non-null details are retained verbatim so API additions do not
247
+ * make older SDK clients reject the entire validation response.
248
+ */
249
+ export type MempoolPayloadValidationIssueDetails = {
250
+ /** Identifies details for the `min_offer_assets_usd` rule. */
251
+ readonly type: "minOfferAssetsUsd";
252
+ /** Loan token of the first offer below its configured minimum. */
253
+ readonly loanToken: Address;
254
+ /** Configured minimum in raw loan-token assets. */
255
+ readonly minAssets: bigint;
256
+ } | {
257
+ /** Identifies details whose schema is not known by this SDK version. */
258
+ readonly type: "unknown";
259
+ /** Unmodified JSON value returned by the API. */
260
+ readonly raw: unknown;
261
+ };
262
+ /**
263
+ * `MempoolPayloadValidationIssue` represents one API validation issue.
198
264
  */
199
265
  export interface MempoolPayloadValidationIssue {
200
266
  /** API rule violated by the payload. */
201
- readonly rule: string;
267
+ readonly rule: MempoolPayloadValidationRule;
268
+ /** Parsed non-null details, when the API provides them. */
269
+ readonly details?: MempoolPayloadValidationIssueDetails;
202
270
  }
203
271
  /**
204
272
  * SDK-shaped result returned by Midnight mempool validation.
@@ -1,2 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MempoolPayloadValidationRule = void 0;
4
+ /**
5
+ * `MempoolPayloadValidationRule` lists known Midnight mempool validation rules.
6
+ */
7
+ exports.MempoolPayloadValidationRule = {
8
+ MinOfferAssetsUsd: "min_offer_assets_usd",
9
+ PayloadVersion: "payload_version",
10
+ PayloadFrame: "payload_frame",
11
+ PayloadGzipLength: "payload_gzip_length",
12
+ PayloadSuffixTooLarge: "payload_suffix_too_large",
13
+ PayloadDecompression: "payload_decompression",
14
+ PayloadAbiDecode: "payload_abi_decode",
15
+ EmptyPayload: "empty_payload",
16
+ MaxOffersPerTree: "max_offers_per_tree",
17
+ DuplicateOfferHash: "duplicate_offer_hash",
18
+ UnsupportedChain: "unsupported_chain",
19
+ MarketChainMismatch: "market_chain_mismatch",
20
+ Maturity: "maturity",
21
+ LoanToken: "loan_token",
22
+ CollateralToken: "collateral_token",
23
+ Oracle: "oracle",
24
+ MarketTriplet: "market_triplet",
25
+ RcfThreshold: "rcf_threshold",
26
+ CollateralLltv: "collateral_lltv",
27
+ MaxLif: "max_lif",
28
+ MaxCollaterals: "max_collaterals",
29
+ AmountMissing: "amount_missing",
30
+ AmountConflict: "amount_conflict",
31
+ MinTick: "min_tick",
32
+ MaxTick: "max_tick",
33
+ TickSpacing: "tick_spacing",
34
+ MinDuration: "min_duration",
35
+ Ratifier: "ratifier",
36
+ MixedMaker: "mixed_maker",
37
+ MixedRatifier: "mixed_ratifier",
38
+ GroupIdentity: "group_identity",
39
+ GroupConsistency: "group_consistency",
40
+ NonEmptyCallback: "non_empty_callback",
41
+ BuyEmptyCallback: "buy_empty_callback",
42
+ SellEmptyCallback: "sell_empty_callback",
43
+ };
@@ -0,0 +1,2 @@
1
+ /** @internal Installed Midnight SDK package version. */
2
+ export declare const MIDNIGHT_SDK_VERSION = "1.3.0";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ // Generated by scripts/release/generate-midnight-package-version.mjs. Do not edit.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.MIDNIGHT_SDK_VERSION = void 0;
5
+ /** @internal Installed Midnight SDK package version. */
6
+ exports.MIDNIGHT_SDK_VERSION = "1.3.0";
@@ -9,9 +9,9 @@ import { type IMarket, type IMarketParams, Market, MarketParams } from "../marke
9
9
  * take-side conversion helpers. Use {@link Offer.create} instead for new maker
10
10
  * offers so deterministic fields are validated before grouping or signing.
11
11
  * The `group` field is optional. When omitted, {@link Offer.group} lazily
12
- * derives the standalone group id from this offer hashed with the protocol
13
- * zero group id. `Group.create` copies offers into a shared group and overrides
14
- * this field on the copies it owns.
12
+ * derives the content-addressed singleton group id from this offer's
13
+ * zero-group hash. `Group.create` copies offers into a shared group and
14
+ * overrides this field on the copies it owns.
15
15
  *
16
16
  * @example
17
17
  * ```ts
@@ -64,7 +64,7 @@ export interface IOffer {
64
64
  readonly expiry: BigIntish;
65
65
  /** Midnight tick. */
66
66
  readonly tick: BigIntish;
67
- /** Consumption group id; defaults to the offer hash with the zero group id. */
67
+ /** Consumption group id; defaults to the content-addressed singleton group id. */
68
68
  readonly group?: Hash;
69
69
  /** Optional maker callback. */
70
70
  readonly callback: Address;
@@ -90,10 +90,11 @@ export interface IOffer {
90
90
  * `Group.create` for shared-consumption ladders or directly to `Tree.create`
91
91
  * for standalone offers. API/take-side code can convert a plain `IOffer`
92
92
  * into this class before ABI encoding. The class resolves the onchain `group`
93
- * field lazily. Standalone offers derive their group id from the offer hash
94
- * with the zero group id; `Group.create` copies offers and overrides the group
95
- * on those copies when several offers share one consumption bucket. Offers
96
- * hydrated from API or decoded data may also carry a known group id.
93
+ * field lazily. Standalone offers derive their content-addressed singleton
94
+ * group id from the offer's zero-group hash; `Group.create` copies offers and
95
+ * overrides the group on those copies when several offers share one
96
+ * consumption bucket. Offers hydrated from API or decoded data may also carry
97
+ * a known group id.
97
98
  *
98
99
  * @example
99
100
  * ```ts
@@ -220,8 +221,11 @@ export declare class Offer {
220
221
  * Consumption group id encoded into this offer.
221
222
  *
222
223
  * When no group id was provided, the value is computed on first access by
223
- * hashing this offer with the protocol zero group id. The computed value is
224
- * cached because offer hashing is resource-intensive.
224
+ * hashing this offer with the protocol zero group id, then hashing that
225
+ * result as a singleton group. The computed value is cached because offer
226
+ * hashing is resource-intensive. This is equivalent to
227
+ * `GroupUtils.hash([offer])`, but is computed directly to keep the offers
228
+ * layer from importing signature helpers and creating a circular dependency.
225
229
  *
226
230
  * @returns Consumption group id.
227
231
  * @example
@@ -11,10 +11,11 @@ const OfferUtils_js_1 = require("./OfferUtils.js");
11
11
  * `Group.create` for shared-consumption ladders or directly to `Tree.create`
12
12
  * for standalone offers. API/take-side code can convert a plain `IOffer`
13
13
  * into this class before ABI encoding. The class resolves the onchain `group`
14
- * field lazily. Standalone offers derive their group id from the offer hash
15
- * with the zero group id; `Group.create` copies offers and overrides the group
16
- * on those copies when several offers share one consumption bucket. Offers
17
- * hydrated from API or decoded data may also carry a known group id.
14
+ * field lazily. Standalone offers derive their content-addressed singleton
15
+ * group id from the offer's zero-group hash; `Group.create` copies offers and
16
+ * overrides the group on those copies when several offers share one
17
+ * consumption bucket. Offers hydrated from API or decoded data may also carry
18
+ * a known group id.
18
19
  *
19
20
  * @example
20
21
  * ```ts
@@ -162,8 +163,11 @@ class Offer {
162
163
  * Consumption group id encoded into this offer.
163
164
  *
164
165
  * When no group id was provided, the value is computed on first access by
165
- * hashing this offer with the protocol zero group id. The computed value is
166
- * cached because offer hashing is resource-intensive.
166
+ * hashing this offer with the protocol zero group id, then hashing that
167
+ * result as a singleton group. The computed value is cached because offer
168
+ * hashing is resource-intensive. This is equivalent to
169
+ * `GroupUtils.hash([offer])`, but is computed directly to keep the offers
170
+ * layer from importing signature helpers and creating a circular dependency.
167
171
  *
168
172
  * @returns Consumption group id.
169
173
  * @example
@@ -208,7 +212,7 @@ class Offer {
208
212
  * ```
209
213
  */
210
214
  get group() {
211
- this.cachedGroup ??= OfferUtils_js_1.OfferUtils.groupHash(this);
215
+ this.cachedGroup ??= (0, viem_1.keccak256)(OfferUtils_js_1.OfferUtils.groupHash(this));
212
216
  return this.cachedGroup;
213
217
  }
214
218
  /**
@@ -24,12 +24,10 @@ function normalizeTree(tree) {
24
24
  : [
25
25
  new index_js_1.Offer({
26
26
  ...index_js_1.Offer.from(entry),
27
- group: index_js_1.OfferUtils.groupHash(entry),
27
+ group: GroupUtils_js_1.GroupUtils.hash([entry]),
28
28
  }),
29
29
  ]);
30
- const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(offers, {
31
- preserveStandaloneGroups: true,
32
- });
30
+ const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(entries);
33
31
  return {
34
32
  offers,
35
33
  paddedOffers: descriptor.offers,
@@ -108,8 +108,9 @@ export declare class Tree {
108
108
  *
109
109
  * Use after `Offer.create` and optional `Group.create`, before
110
110
  * `Tree.mempoolValidate`, `EcrecoverRatifierUtils.ratify`, or
111
- * `SetterRatifierUtils.ratify`. Groups are flattened; the tree hashes each
112
- * offer with the group id already stored on the offer.
111
+ * `SetterRatifierUtils.ratify`. Groups are flattened, and every standalone
112
+ * offer is normalized as a singleton group using the router-compatible group
113
+ * id algorithm.
113
114
  *
114
115
  * @param params - Groups or standalone offers in leaf order.
115
116
  * @returns Tree instance.
@@ -63,7 +63,7 @@ class Tree {
63
63
  : [
64
64
  new index_js_1.Offer({
65
65
  ...index_js_1.Offer.from(entry),
66
- group: index_js_1.OfferUtils.groupHash(entry),
66
+ group: GroupUtils_js_1.GroupUtils.hash([entry]),
67
67
  }),
68
68
  ]);
69
69
  const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(params);
@@ -127,8 +127,9 @@ class Tree {
127
127
  *
128
128
  * Use after `Offer.create` and optional `Group.create`, before
129
129
  * `Tree.mempoolValidate`, `EcrecoverRatifierUtils.ratify`, or
130
- * `SetterRatifierUtils.ratify`. Groups are flattened; the tree hashes each
131
- * offer with the group id already stored on the offer.
130
+ * `SetterRatifierUtils.ratify`. Groups are flattened, and every standalone
131
+ * offer is normalized as a singleton group using the router-compatible group
132
+ * id algorithm.
132
133
  *
133
134
  * @param params - Groups or standalone offers in leaf order.
134
135
  * @returns Tree instance.
@@ -489,12 +489,11 @@ export declare namespace TreeUtils {
489
489
  * Use after `Group.create` or standalone `Offer.create` when you need the
490
490
  * padded leaves for custom signing, root approval, or proof construction.
491
491
  * Groups are encoded with their derived shared group id, and standalone
492
- * offers are encoded with their own group id.
492
+ * offers are encoded as singleton groups with the same algorithm.
493
493
  * `Tree.create` calls this internally and is the simpler API for most
494
494
  * make-side code.
495
495
  *
496
496
  * @param entries - Groups or standalone offers in leaf order.
497
- * @param options.preserveStandaloneGroups - Whether standalone offer group ids should be preserved instead of normalized.
498
497
  * @returns Tree descriptor.
499
498
  * @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
500
499
  * @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
@@ -532,9 +531,7 @@ export declare namespace TreeUtils {
532
531
  * console.log(tree.root);
533
532
  * ```
534
533
  */
535
- function buildDescriptor(entries: TreeCreateParams, options?: {
536
- readonly preserveStandaloneGroups?: boolean;
537
- }): TreeDescriptor;
534
+ function buildDescriptor(entries: TreeCreateParams): TreeDescriptor;
538
535
  /**
539
536
  * Builds only the tree root.
540
537
  *
@@ -137,10 +137,10 @@ var TreeUtils;
137
137
  : [
138
138
  new index_js_1.Offer({
139
139
  ...index_js_1.Offer.from(entry),
140
- group: index_js_1.OfferUtils.groupHash(entry),
140
+ group: GroupUtils_js_1.GroupUtils.hash([entry]),
141
141
  }),
142
142
  ]);
143
- buildDescriptor(offers, { preserveStandaloneGroups: true });
143
+ buildDescriptor(entries);
144
144
  items = offers.map((offer) => ({
145
145
  offer,
146
146
  ratifierData: "0x",
@@ -209,12 +209,11 @@ var TreeUtils;
209
209
  * Use after `Group.create` or standalone `Offer.create` when you need the
210
210
  * padded leaves for custom signing, root approval, or proof construction.
211
211
  * Groups are encoded with their derived shared group id, and standalone
212
- * offers are encoded with their own group id.
212
+ * offers are encoded as singleton groups with the same algorithm.
213
213
  * `Tree.create` calls this internally and is the simpler API for most
214
214
  * make-side code.
215
215
  *
216
216
  * @param entries - Groups or standalone offers in leaf order.
217
- * @param options.preserveStandaloneGroups - Whether standalone offer group ids should be preserved instead of normalized.
218
217
  * @returns Tree descriptor.
219
218
  * @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
220
219
  * @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
@@ -252,15 +251,13 @@ var TreeUtils;
252
251
  * console.log(tree.root);
253
252
  * ```
254
253
  */
255
- function buildDescriptor(entries, options = {}) {
254
+ function buildDescriptor(entries) {
256
255
  const structs = entries.flatMap((entry) => GroupUtils_js_1.GroupUtils.isGroupInput(entry)
257
256
  ? GroupUtils_js_1.GroupUtils.toStructs(entry)
258
257
  : [
259
258
  index_js_1.OfferUtils.toStruct({
260
259
  offer: entry,
261
- group: options.preserveStandaloneGroups
262
- ? undefined
263
- : index_js_1.OfferUtils.groupHash(entry),
260
+ group: GroupUtils_js_1.GroupUtils.hash([entry]),
264
261
  }),
265
262
  ]);
266
263
  if (structs.length === 0) {
@@ -1,5 +1,6 @@
1
1
  import type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationResult, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiConstructorConfig, MidnightApiQuoteResult, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams } from "./types.js";
2
- export type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationIssue, MempoolPayloadValidationResult, MempoolPayloadValidationSuccess, MidnightApiBookMarket, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBookSide, MidnightApiBookSort, MidnightApiBookSortField, MidnightApiBookSortTerm, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiCollateral, MidnightApiConfig, MidnightApiConstructorConfig, MidnightApiFetch, MidnightApiPriceLevel, MidnightApiQuote, MidnightApiQuoteAssetsTarget, MidnightApiQuoteAverageWorstPriceGuard, MidnightApiQuoteResult, MidnightApiQuoteSlippageGuard, MidnightApiQuoteUnitsTarget, MidnightApiQuoteWithoutGuard, MidnightApiRequestOptions, MidnightApiSlippage, MidnightApiTake, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams, } from "./types.js";
2
+ export type { FetchBookParams, FetchBookPriceLevelsParams, FetchBookQuoteParams, FetchBooksParams, FetchBookTakeableOffersParams, FetchTakeableOffersParams, MempoolPayloadValidationIssue, MempoolPayloadValidationIssueDetails, MempoolPayloadValidationResult, MempoolPayloadValidationSuccess, MidnightApiBookMarket, MidnightApiBookPriceLevelsResult, MidnightApiBookResult, MidnightApiBookSide, MidnightApiBookSort, MidnightApiBookSortField, MidnightApiBookSortTerm, MidnightApiBooksResult, MidnightApiBookTakeableOffersResult, MidnightApiClientParams, MidnightApiCollateral, MidnightApiConfig, MidnightApiConstructorConfig, MidnightApiFetch, MidnightApiPriceLevel, MidnightApiQuote, MidnightApiQuoteAssetsTarget, MidnightApiQuoteAverageWorstPriceGuard, MidnightApiQuoteResult, MidnightApiQuoteSlippageGuard, MidnightApiQuoteUnitsTarget, MidnightApiQuoteWithoutGuard, MidnightApiRequestOptions, MidnightApiSlippage, MidnightApiTake, MidnightApiTakeableOffersResult, ValidateMempoolItemsParams, ValidateMempoolPayloadParams, } from "./types.js";
3
+ export { MempoolPayloadValidationRule } from "./types.js";
3
4
  /**
4
5
  * Midnight API client and stateless helper surface for books and mempool data.
5
6
  *
@@ -3,6 +3,7 @@ import { InvalidMidnightApiResponseError } from "../errors.js";
3
3
  import { TickLib } from "../math/index.js";
4
4
  import { Payload } from "../signatures/Payload.js";
5
5
  import { buildBookPath, mapBookMarket, mapBoundTakeableOffers, mapPriceLevel, parseValidationResponse, requestMidnightApi, } from "./helpers.js";
6
+ export { MempoolPayloadValidationRule } from "./types.js";
6
7
  /**
7
8
  * Midnight API client and stateless helper surface for books and mempool data.
8
9
  *
@@ -1,5 +1,5 @@
1
1
  import { type Address, type Hash } from "viem";
2
- import type { ApiBookMarketResponse, ApiCollateralResponse, ApiPriceLevelResponse, ApiRequestParams, ApiTakeableOfferResponse, MempoolPayloadValidationResult, MidnightApiBookMarket, MidnightApiBookSide, MidnightApiCollateral, MidnightApiPriceLevel, MidnightApiTake } from "./types.js";
2
+ import { type ApiBookMarketResponse, type ApiCollateralResponse, type ApiPriceLevelResponse, type ApiRequestParams, type ApiTakeableOfferResponse, type MempoolPayloadValidationResult, type MidnightApiBookMarket, type MidnightApiBookSide, type MidnightApiCollateral, type MidnightApiPriceLevel, type MidnightApiTake } from "./types.js";
3
3
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
4
4
  export declare function requestMidnightApi<Response = unknown>(params: ApiRequestParams): Promise<Response>;
5
5
  /** @internal Builds a book endpoint path with encoded path segments. */
@@ -1,11 +1,11 @@
1
1
  import { BLUE_API_BASE_URL, isHexEqual } from "@morpho-org/morpho-ts";
2
- import { isAddressEqual } from "viem";
2
+ import { isAddress, isAddressEqual, maxUint256, } from "viem";
3
3
  import { InvalidMidnightApiResponseError, MidnightApiError, } from "../errors.js";
4
4
  import { MarketUtils } from "../market/index.js";
5
+ import { MempoolPayloadValidationRule, } from "./types.js";
6
+ import { MIDNIGHT_SDK_VERSION } from "./version.generated.js";
5
7
  const DEFAULT_MIDNIGHT_API_URL = new URL("/v0/midnight", BLUE_API_BASE_URL);
6
- // Keep this literal in source so the browser ESM build does not import package.json
7
- // through Node-only createRequire/module shims.
8
- const MIDNIGHT_SDK_VERSION = "1.0.1";
8
+ const MAX_UINT256_DECIMAL_LENGTH = maxUint256.toString().length;
9
9
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
10
10
  export async function requestMidnightApi(params) {
11
11
  const baseUrl = new URL(params.baseUrl ?? DEFAULT_MIDNIGHT_API_URL);
@@ -212,7 +212,38 @@ export function parseValidationResponse(response) {
212
212
  if (typeof rule !== "string") {
213
213
  throw new InvalidMidnightApiResponseError('Midnight API validation issue is missing "rule".');
214
214
  }
215
- return { rule };
215
+ const details = record.details;
216
+ if (details == null)
217
+ return { rule };
218
+ if (rule === MempoolPayloadValidationRule.MinOfferAssetsUsd &&
219
+ isRecord(details)) {
220
+ const loanToken = details.loan_token;
221
+ const rawMinAssets = details.min_assets;
222
+ if (typeof loanToken === "string" &&
223
+ isAddress(loanToken) &&
224
+ typeof rawMinAssets === "string" &&
225
+ rawMinAssets.length <= MAX_UINT256_DECIMAL_LENGTH &&
226
+ /^\d+$/.test(rawMinAssets)) {
227
+ const minAssets = BigInt(rawMinAssets);
228
+ if (minAssets <= maxUint256) {
229
+ return {
230
+ rule,
231
+ details: {
232
+ type: "minOfferAssetsUsd",
233
+ loanToken,
234
+ minAssets,
235
+ },
236
+ };
237
+ }
238
+ }
239
+ }
240
+ return {
241
+ rule,
242
+ details: {
243
+ type: "unknown",
244
+ raw: details,
245
+ },
246
+ };
216
247
  });
217
248
  return {
218
249
  valid: issues.length === 0,
@@ -194,11 +194,79 @@ export interface FetchTakeableOffersParams extends MidnightApiConfig {
194
194
  readonly cursor?: string;
195
195
  }
196
196
  /**
197
- * One API validation issue.
197
+ * `MempoolPayloadValidationRule` lists known Midnight mempool validation rules.
198
+ */
199
+ export declare const MempoolPayloadValidationRule: {
200
+ readonly MinOfferAssetsUsd: "min_offer_assets_usd";
201
+ readonly PayloadVersion: "payload_version";
202
+ readonly PayloadFrame: "payload_frame";
203
+ readonly PayloadGzipLength: "payload_gzip_length";
204
+ readonly PayloadSuffixTooLarge: "payload_suffix_too_large";
205
+ readonly PayloadDecompression: "payload_decompression";
206
+ readonly PayloadAbiDecode: "payload_abi_decode";
207
+ readonly EmptyPayload: "empty_payload";
208
+ readonly MaxOffersPerTree: "max_offers_per_tree";
209
+ readonly DuplicateOfferHash: "duplicate_offer_hash";
210
+ readonly UnsupportedChain: "unsupported_chain";
211
+ readonly MarketChainMismatch: "market_chain_mismatch";
212
+ readonly Maturity: "maturity";
213
+ readonly LoanToken: "loan_token";
214
+ readonly CollateralToken: "collateral_token";
215
+ readonly Oracle: "oracle";
216
+ readonly MarketTriplet: "market_triplet";
217
+ readonly RcfThreshold: "rcf_threshold";
218
+ readonly CollateralLltv: "collateral_lltv";
219
+ readonly MaxLif: "max_lif";
220
+ readonly MaxCollaterals: "max_collaterals";
221
+ readonly AmountMissing: "amount_missing";
222
+ readonly AmountConflict: "amount_conflict";
223
+ readonly MinTick: "min_tick";
224
+ readonly MaxTick: "max_tick";
225
+ readonly TickSpacing: "tick_spacing";
226
+ readonly MinDuration: "min_duration";
227
+ readonly Ratifier: "ratifier";
228
+ readonly MixedMaker: "mixed_maker";
229
+ readonly MixedRatifier: "mixed_ratifier";
230
+ readonly GroupIdentity: "group_identity";
231
+ readonly GroupConsistency: "group_consistency";
232
+ readonly NonEmptyCallback: "non_empty_callback";
233
+ readonly BuyEmptyCallback: "buy_empty_callback";
234
+ readonly SellEmptyCallback: "sell_empty_callback";
235
+ };
236
+ /**
237
+ * `MempoolPayloadValidationRule` represents a rule returned by the API.
238
+ *
239
+ * Known values have autocomplete through the matching constant; the open
240
+ * string branch keeps newer API rules forward-compatible.
241
+ */
242
+ export type MempoolPayloadValidationRule = (typeof MempoolPayloadValidationRule)[keyof typeof MempoolPayloadValidationRule] | (string & Record<never, never>);
243
+ /**
244
+ * `MempoolPayloadValidationIssueDetails` represents parsed issue details.
245
+ *
246
+ * Unrecognized non-null details are retained verbatim so API additions do not
247
+ * make older SDK clients reject the entire validation response.
248
+ */
249
+ export type MempoolPayloadValidationIssueDetails = {
250
+ /** Identifies details for the `min_offer_assets_usd` rule. */
251
+ readonly type: "minOfferAssetsUsd";
252
+ /** Loan token of the first offer below its configured minimum. */
253
+ readonly loanToken: Address;
254
+ /** Configured minimum in raw loan-token assets. */
255
+ readonly minAssets: bigint;
256
+ } | {
257
+ /** Identifies details whose schema is not known by this SDK version. */
258
+ readonly type: "unknown";
259
+ /** Unmodified JSON value returned by the API. */
260
+ readonly raw: unknown;
261
+ };
262
+ /**
263
+ * `MempoolPayloadValidationIssue` represents one API validation issue.
198
264
  */
199
265
  export interface MempoolPayloadValidationIssue {
200
266
  /** API rule violated by the payload. */
201
- readonly rule: string;
267
+ readonly rule: MempoolPayloadValidationRule;
268
+ /** Parsed non-null details, when the API provides them. */
269
+ readonly details?: MempoolPayloadValidationIssueDetails;
202
270
  }
203
271
  /**
204
272
  * SDK-shaped result returned by Midnight mempool validation.
@@ -1 +1,40 @@
1
- export {};
1
+ /**
2
+ * `MempoolPayloadValidationRule` lists known Midnight mempool validation rules.
3
+ */
4
+ export const MempoolPayloadValidationRule = {
5
+ MinOfferAssetsUsd: "min_offer_assets_usd",
6
+ PayloadVersion: "payload_version",
7
+ PayloadFrame: "payload_frame",
8
+ PayloadGzipLength: "payload_gzip_length",
9
+ PayloadSuffixTooLarge: "payload_suffix_too_large",
10
+ PayloadDecompression: "payload_decompression",
11
+ PayloadAbiDecode: "payload_abi_decode",
12
+ EmptyPayload: "empty_payload",
13
+ MaxOffersPerTree: "max_offers_per_tree",
14
+ DuplicateOfferHash: "duplicate_offer_hash",
15
+ UnsupportedChain: "unsupported_chain",
16
+ MarketChainMismatch: "market_chain_mismatch",
17
+ Maturity: "maturity",
18
+ LoanToken: "loan_token",
19
+ CollateralToken: "collateral_token",
20
+ Oracle: "oracle",
21
+ MarketTriplet: "market_triplet",
22
+ RcfThreshold: "rcf_threshold",
23
+ CollateralLltv: "collateral_lltv",
24
+ MaxLif: "max_lif",
25
+ MaxCollaterals: "max_collaterals",
26
+ AmountMissing: "amount_missing",
27
+ AmountConflict: "amount_conflict",
28
+ MinTick: "min_tick",
29
+ MaxTick: "max_tick",
30
+ TickSpacing: "tick_spacing",
31
+ MinDuration: "min_duration",
32
+ Ratifier: "ratifier",
33
+ MixedMaker: "mixed_maker",
34
+ MixedRatifier: "mixed_ratifier",
35
+ GroupIdentity: "group_identity",
36
+ GroupConsistency: "group_consistency",
37
+ NonEmptyCallback: "non_empty_callback",
38
+ BuyEmptyCallback: "buy_empty_callback",
39
+ SellEmptyCallback: "sell_empty_callback",
40
+ };
@@ -0,0 +1,2 @@
1
+ /** @internal Installed Midnight SDK package version. */
2
+ export declare const MIDNIGHT_SDK_VERSION = "1.3.0";
@@ -0,0 +1,3 @@
1
+ // Generated by scripts/release/generate-midnight-package-version.mjs. Do not edit.
2
+ /** @internal Installed Midnight SDK package version. */
3
+ export const MIDNIGHT_SDK_VERSION = "1.3.0";
@@ -9,9 +9,9 @@ import { type IMarket, type IMarketParams, Market, MarketParams } from "../marke
9
9
  * take-side conversion helpers. Use {@link Offer.create} instead for new maker
10
10
  * offers so deterministic fields are validated before grouping or signing.
11
11
  * The `group` field is optional. When omitted, {@link Offer.group} lazily
12
- * derives the standalone group id from this offer hashed with the protocol
13
- * zero group id. `Group.create` copies offers into a shared group and overrides
14
- * this field on the copies it owns.
12
+ * derives the content-addressed singleton group id from this offer's
13
+ * zero-group hash. `Group.create` copies offers into a shared group and
14
+ * overrides this field on the copies it owns.
15
15
  *
16
16
  * @example
17
17
  * ```ts
@@ -64,7 +64,7 @@ export interface IOffer {
64
64
  readonly expiry: BigIntish;
65
65
  /** Midnight tick. */
66
66
  readonly tick: BigIntish;
67
- /** Consumption group id; defaults to the offer hash with the zero group id. */
67
+ /** Consumption group id; defaults to the content-addressed singleton group id. */
68
68
  readonly group?: Hash;
69
69
  /** Optional maker callback. */
70
70
  readonly callback: Address;
@@ -90,10 +90,11 @@ export interface IOffer {
90
90
  * `Group.create` for shared-consumption ladders or directly to `Tree.create`
91
91
  * for standalone offers. API/take-side code can convert a plain `IOffer`
92
92
  * into this class before ABI encoding. The class resolves the onchain `group`
93
- * field lazily. Standalone offers derive their group id from the offer hash
94
- * with the zero group id; `Group.create` copies offers and overrides the group
95
- * on those copies when several offers share one consumption bucket. Offers
96
- * hydrated from API or decoded data may also carry a known group id.
93
+ * field lazily. Standalone offers derive their content-addressed singleton
94
+ * group id from the offer's zero-group hash; `Group.create` copies offers and
95
+ * overrides the group on those copies when several offers share one
96
+ * consumption bucket. Offers hydrated from API or decoded data may also carry
97
+ * a known group id.
97
98
  *
98
99
  * @example
99
100
  * ```ts
@@ -220,8 +221,11 @@ export declare class Offer {
220
221
  * Consumption group id encoded into this offer.
221
222
  *
222
223
  * When no group id was provided, the value is computed on first access by
223
- * hashing this offer with the protocol zero group id. The computed value is
224
- * cached because offer hashing is resource-intensive.
224
+ * hashing this offer with the protocol zero group id, then hashing that
225
+ * result as a singleton group. The computed value is cached because offer
226
+ * hashing is resource-intensive. This is equivalent to
227
+ * `GroupUtils.hash([offer])`, but is computed directly to keep the offers
228
+ * layer from importing signature helpers and creating a circular dependency.
225
229
  *
226
230
  * @returns Consumption group id.
227
231
  * @example
@@ -1,4 +1,4 @@
1
- import { zeroAddress } from "viem";
1
+ import { keccak256, zeroAddress } from "viem";
2
2
  import { Market, MarketParams, } from "../market/index.js";
3
3
  import { OfferUtils } from "./OfferUtils.js";
4
4
  /**
@@ -8,10 +8,11 @@ import { OfferUtils } from "./OfferUtils.js";
8
8
  * `Group.create` for shared-consumption ladders or directly to `Tree.create`
9
9
  * for standalone offers. API/take-side code can convert a plain `IOffer`
10
10
  * into this class before ABI encoding. The class resolves the onchain `group`
11
- * field lazily. Standalone offers derive their group id from the offer hash
12
- * with the zero group id; `Group.create` copies offers and overrides the group
13
- * on those copies when several offers share one consumption bucket. Offers
14
- * hydrated from API or decoded data may also carry a known group id.
11
+ * field lazily. Standalone offers derive their content-addressed singleton
12
+ * group id from the offer's zero-group hash; `Group.create` copies offers and
13
+ * overrides the group on those copies when several offers share one
14
+ * consumption bucket. Offers hydrated from API or decoded data may also carry
15
+ * a known group id.
15
16
  *
16
17
  * @example
17
18
  * ```ts
@@ -159,8 +160,11 @@ export class Offer {
159
160
  * Consumption group id encoded into this offer.
160
161
  *
161
162
  * When no group id was provided, the value is computed on first access by
162
- * hashing this offer with the protocol zero group id. The computed value is
163
- * cached because offer hashing is resource-intensive.
163
+ * hashing this offer with the protocol zero group id, then hashing that
164
+ * result as a singleton group. The computed value is cached because offer
165
+ * hashing is resource-intensive. This is equivalent to
166
+ * `GroupUtils.hash([offer])`, but is computed directly to keep the offers
167
+ * layer from importing signature helpers and creating a circular dependency.
164
168
  *
165
169
  * @returns Consumption group id.
166
170
  * @example
@@ -205,7 +209,7 @@ export class Offer {
205
209
  * ```
206
210
  */
207
211
  get group() {
208
- this.cachedGroup ??= OfferUtils.groupHash(this);
212
+ this.cachedGroup ??= keccak256(OfferUtils.groupHash(this));
209
213
  return this.cachedGroup;
210
214
  }
211
215
  /**
@@ -1,5 +1,5 @@
1
1
  import { InvalidTreeError } from "../errors.js";
2
- import { Offer, OfferUtils } from "../offers/index.js";
2
+ import { Offer } from "../offers/index.js";
3
3
  import { Group } from "./Group.js";
4
4
  import { GroupUtils } from "./GroupUtils.js";
5
5
  import { TreeUtils } from "./TreeUtils.js";
@@ -21,12 +21,10 @@ function normalizeTree(tree) {
21
21
  : [
22
22
  new Offer({
23
23
  ...Offer.from(entry),
24
- group: OfferUtils.groupHash(entry),
24
+ group: GroupUtils.hash([entry]),
25
25
  }),
26
26
  ]);
27
- const descriptor = TreeUtils.buildDescriptor(offers, {
28
- preserveStandaloneGroups: true,
29
- });
27
+ const descriptor = TreeUtils.buildDescriptor(entries);
30
28
  return {
31
29
  offers,
32
30
  paddedOffers: descriptor.offers,
@@ -108,8 +108,9 @@ export declare class Tree {
108
108
  *
109
109
  * Use after `Offer.create` and optional `Group.create`, before
110
110
  * `Tree.mempoolValidate`, `EcrecoverRatifierUtils.ratify`, or
111
- * `SetterRatifierUtils.ratify`. Groups are flattened; the tree hashes each
112
- * offer with the group id already stored on the offer.
111
+ * `SetterRatifierUtils.ratify`. Groups are flattened, and every standalone
112
+ * offer is normalized as a singleton group using the router-compatible group
113
+ * id algorithm.
113
114
  *
114
115
  * @param params - Groups or standalone offers in leaf order.
115
116
  * @returns Tree instance.
@@ -1,4 +1,4 @@
1
- import { Offer, OfferUtils, } from "../offers/index.js";
1
+ import { Offer } from "../offers/index.js";
2
2
  import { Group } from "./Group.js";
3
3
  import { GroupUtils } from "./GroupUtils.js";
4
4
  import { TreeUtils, } from "./TreeUtils.js";
@@ -60,7 +60,7 @@ export class Tree {
60
60
  : [
61
61
  new Offer({
62
62
  ...Offer.from(entry),
63
- group: OfferUtils.groupHash(entry),
63
+ group: GroupUtils.hash([entry]),
64
64
  }),
65
65
  ]);
66
66
  const descriptor = TreeUtils.buildDescriptor(params);
@@ -124,8 +124,9 @@ export class Tree {
124
124
  *
125
125
  * Use after `Offer.create` and optional `Group.create`, before
126
126
  * `Tree.mempoolValidate`, `EcrecoverRatifierUtils.ratify`, or
127
- * `SetterRatifierUtils.ratify`. Groups are flattened; the tree hashes each
128
- * offer with the group id already stored on the offer.
127
+ * `SetterRatifierUtils.ratify`. Groups are flattened, and every standalone
128
+ * offer is normalized as a singleton group using the router-compatible group
129
+ * id algorithm.
129
130
  *
130
131
  * @param params - Groups or standalone offers in leaf order.
131
132
  * @returns Tree instance.
@@ -489,12 +489,11 @@ export declare namespace TreeUtils {
489
489
  * Use after `Group.create` or standalone `Offer.create` when you need the
490
490
  * padded leaves for custom signing, root approval, or proof construction.
491
491
  * Groups are encoded with their derived shared group id, and standalone
492
- * offers are encoded with their own group id.
492
+ * offers are encoded as singleton groups with the same algorithm.
493
493
  * `Tree.create` calls this internally and is the simpler API for most
494
494
  * make-side code.
495
495
  *
496
496
  * @param entries - Groups or standalone offers in leaf order.
497
- * @param options.preserveStandaloneGroups - Whether standalone offer group ids should be preserved instead of normalized.
498
497
  * @returns Tree descriptor.
499
498
  * @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
500
499
  * @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
@@ -532,9 +531,7 @@ export declare namespace TreeUtils {
532
531
  * console.log(tree.root);
533
532
  * ```
534
533
  */
535
- function buildDescriptor(entries: TreeCreateParams, options?: {
536
- readonly preserveStandaloneGroups?: boolean;
537
- }): TreeDescriptor;
534
+ function buildDescriptor(entries: TreeCreateParams): TreeDescriptor;
538
535
  /**
539
536
  * Builds only the tree root.
540
537
  *
@@ -134,10 +134,10 @@ export var TreeUtils;
134
134
  : [
135
135
  new Offer({
136
136
  ...Offer.from(entry),
137
- group: OfferUtils.groupHash(entry),
137
+ group: GroupUtils.hash([entry]),
138
138
  }),
139
139
  ]);
140
- buildDescriptor(offers, { preserveStandaloneGroups: true });
140
+ buildDescriptor(entries);
141
141
  items = offers.map((offer) => ({
142
142
  offer,
143
143
  ratifierData: "0x",
@@ -206,12 +206,11 @@ export var TreeUtils;
206
206
  * Use after `Group.create` or standalone `Offer.create` when you need the
207
207
  * padded leaves for custom signing, root approval, or proof construction.
208
208
  * Groups are encoded with their derived shared group id, and standalone
209
- * offers are encoded with their own group id.
209
+ * offers are encoded as singleton groups with the same algorithm.
210
210
  * `Tree.create` calls this internally and is the simpler API for most
211
211
  * make-side code.
212
212
  *
213
213
  * @param entries - Groups or standalone offers in leaf order.
214
- * @param options.preserveStandaloneGroups - Whether standalone offer group ids should be preserved instead of normalized.
215
214
  * @returns Tree descriptor.
216
215
  * @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
217
216
  * @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
@@ -249,15 +248,13 @@ export var TreeUtils;
249
248
  * console.log(tree.root);
250
249
  * ```
251
250
  */
252
- function buildDescriptor(entries, options = {}) {
251
+ function buildDescriptor(entries) {
253
252
  const structs = entries.flatMap((entry) => GroupUtils.isGroupInput(entry)
254
253
  ? GroupUtils.toStructs(entry)
255
254
  : [
256
255
  OfferUtils.toStruct({
257
256
  offer: entry,
258
- group: options.preserveStandaloneGroups
259
- ? undefined
260
- : OfferUtils.groupHash(entry),
257
+ group: GroupUtils.hash([entry]),
261
258
  }),
262
259
  ]);
263
260
  if (structs.length === 0) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
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": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "author": "Morpho Association <contact@morpho.org>",
6
6
  "contributors": [
7
7
  "Rubilmax <rmilon@gmail.com>"
@@ -57,9 +57,10 @@
57
57
  "scripts": {
58
58
  "prepublish": "$npm_execpath build",
59
59
  "compile": "node ../../scripts/compile-solidity.js midnight-sdk",
60
- "build": "tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
60
+ "build": "$npm_execpath generate:version && tsc --noEmit && $npm_execpath build:cjs && $npm_execpath build:esm",
61
61
  "build:cjs": "tsc --build tsconfig.build.cjs.json && echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json",
62
62
  "build:esm": "tsc --build tsconfig.build.esm.json && echo '{\"type\":\"module\"}' > lib/esm/package.json",
63
+ "generate:version": "node ../../scripts/release/generate-midnight-package-version.mjs",
63
64
  "test": "vitest --root ../.. --project midnight-sdk"
64
65
  },
65
66
  "types": "./lib/esm/index.d.ts"