@morpho-org/midnight-sdk 1.2.1 → 1.3.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.
@@ -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
  *
@@ -66,7 +67,7 @@ export declare class MidnightApi {
66
67
  * @param params.request - Optional fetch options forwarded to this request.
67
68
  * @returns Paginated books mapped to SDK camelCase fields.
68
69
  * @throws {MidnightApiError} when the API returns a non-2xx response.
69
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
70
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
70
71
  * @example
71
72
  * ```ts
72
73
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -91,7 +92,7 @@ export declare class MidnightApi {
91
92
  * @param params.request - Optional fetch options forwarded to this request.
92
93
  * @returns Book snapshot mapped to SDK camelCase fields.
93
94
  * @throws {MidnightApiError} when the API returns a non-2xx response.
94
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
95
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
95
96
  * @example
96
97
  * ```ts
97
98
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -319,7 +320,7 @@ export declare class MidnightApi {
319
320
  * @param params.cursor - Optional opaque pagination cursor from a previous response.
320
321
  * @returns Paginated books mapped to SDK camelCase fields.
321
322
  * @throws {MidnightApiError} when the API returns a non-2xx response.
322
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
323
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
323
324
  * @example
324
325
  * ```ts
325
326
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -339,7 +340,7 @@ export declare class MidnightApi {
339
340
  * @param params.depth - Optional maximum levels returned per side.
340
341
  * @returns Book snapshot mapped to SDK camelCase fields.
341
342
  * @throws {MidnightApiError} when the API returns a non-2xx response.
342
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
343
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
343
344
  * @example
344
345
  * ```ts
345
346
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -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
  *
@@ -77,7 +79,7 @@ class MidnightApi {
77
79
  * @param params.request - Optional fetch options forwarded to this request.
78
80
  * @returns Paginated books mapped to SDK camelCase fields.
79
81
  * @throws {MidnightApiError} when the API returns a non-2xx response.
80
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
82
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
81
83
  * @example
82
84
  * ```ts
83
85
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -108,7 +110,7 @@ class MidnightApi {
108
110
  });
109
111
  return {
110
112
  cursor: response.cursor,
111
- data: response.data.map(helpers_js_1.mapBookMarket),
113
+ data: (0, helpers_js_1.mapBoundBooks)(response.data, input.marketIds),
112
114
  };
113
115
  }
114
116
  /**
@@ -123,7 +125,7 @@ class MidnightApi {
123
125
  * @param params.request - Optional fetch options forwarded to this request.
124
126
  * @returns Book snapshot mapped to SDK camelCase fields.
125
127
  * @throws {MidnightApiError} when the API returns a non-2xx response.
126
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
128
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
127
129
  * @example
128
130
  * ```ts
129
131
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -145,7 +147,7 @@ class MidnightApi {
145
147
  },
146
148
  });
147
149
  return {
148
- data: (0, helpers_js_1.mapBookMarket)(response.data),
150
+ data: (0, helpers_js_1.mapBoundBookMarket)(response.data, input.marketId),
149
151
  };
150
152
  }
151
153
  /**
@@ -523,7 +525,7 @@ class MidnightApi {
523
525
  * @param params.cursor - Optional opaque pagination cursor from a previous response.
524
526
  * @returns Paginated books mapped to SDK camelCase fields.
525
527
  * @throws {MidnightApiError} when the API returns a non-2xx response.
526
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
528
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
527
529
  * @example
528
530
  * ```ts
529
531
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -548,7 +550,7 @@ class MidnightApi {
548
550
  * @param params.depth - Optional maximum levels returned per side.
549
551
  * @returns Book snapshot mapped to SDK camelCase fields.
550
552
  * @throws {MidnightApiError} when the API returns a non-2xx response.
551
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
553
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
552
554
  * @example
553
555
  * ```ts
554
556
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -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. */
@@ -8,8 +8,18 @@ export declare function buildBookPath(params: {
8
8
  readonly side?: MidnightApiBookSide;
9
9
  readonly suffix?: "quote" | "takeable-offers";
10
10
  }): string;
11
- /** @internal Maps a book market API payload to the SDK response shape. */
11
+ /**
12
+ * @internal Maps a book market API payload to the SDK response shape, rejecting any
13
+ * response whose advertised `market_id` cannot be derived from — or does not match —
14
+ * its own market params. Recomputing the id with `MarketUtils.toId` (mirroring the
15
+ * takeable-offers path) stops a hostile API from pairing a trusted id with foreign
16
+ * metadata; every book flows through here, so both bound paths reject the same substitution.
17
+ */
12
18
  export declare function mapBookMarket(book: ApiBookMarketResponse): MidnightApiBookMarket;
19
+ /** @internal Maps a book market, binding its verified id to the requested market. */
20
+ export declare function mapBoundBookMarket(book: ApiBookMarketResponse, requestedMarketId: Hash): MidnightApiBookMarket;
21
+ /** @internal Maps listed book markets, binding each verified id to the requested market_ids filter when present. */
22
+ export declare function mapBoundBooks(books: readonly ApiBookMarketResponse[], marketIds?: readonly Hash[]): MidnightApiBookMarket[];
13
23
  /** @internal Maps a collateral API payload to the SDK response shape. */
14
24
  export declare function mapCollateral(collateral: ApiCollateralResponse): MidnightApiCollateral;
15
25
  /** @internal Maps a price-level API payload to the SDK response shape. */
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.requestMidnightApi = requestMidnightApi;
4
4
  exports.buildBookPath = buildBookPath;
5
5
  exports.mapBookMarket = mapBookMarket;
6
+ exports.mapBoundBookMarket = mapBoundBookMarket;
7
+ exports.mapBoundBooks = mapBoundBooks;
6
8
  exports.mapCollateral = mapCollateral;
7
9
  exports.mapPriceLevel = mapPriceLevel;
8
10
  exports.mapTakeableOffer = mapTakeableOffer;
@@ -12,8 +14,10 @@ const morpho_ts_1 = require("@morpho-org/morpho-ts");
12
14
  const viem_1 = require("viem");
13
15
  const errors_js_1 = require("../errors.js");
14
16
  const index_js_1 = require("../market/index.js");
17
+ const types_js_1 = require("./types.js");
15
18
  const version_generated_js_1 = require("./version.generated.js");
16
19
  const DEFAULT_MIDNIGHT_API_URL = new URL("/v0/midnight", morpho_ts_1.BLUE_API_BASE_URL);
20
+ const MAX_UINT256_DECIMAL_LENGTH = viem_1.maxUint256.toString().length;
17
21
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
18
22
  async function requestMidnightApi(params) {
19
23
  const baseUrl = new URL(params.baseUrl ?? DEFAULT_MIDNIGHT_API_URL);
@@ -88,8 +92,42 @@ function buildBookPath(params) {
88
92
  ].filter((segment) => segment !== undefined);
89
93
  return segments.map(encodeURIComponent).join("/");
90
94
  }
91
- /** @internal Maps a book market API payload to the SDK response shape. */
95
+ /**
96
+ * @internal Maps a book market API payload to the SDK response shape, rejecting any
97
+ * response whose advertised `market_id` cannot be derived from — or does not match —
98
+ * its own market params. Recomputing the id with `MarketUtils.toId` (mirroring the
99
+ * takeable-offers path) stops a hostile API from pairing a trusted id with foreign
100
+ * metadata; every book flows through here, so both bound paths reject the same substitution.
101
+ */
92
102
  function mapBookMarket(book) {
103
+ let derivedMarketId;
104
+ let matchesAdvertisedId;
105
+ try {
106
+ derivedMarketId = index_js_1.MarketUtils.toId({
107
+ chainId: book.chain_id,
108
+ midnight: book.midnight,
109
+ loanToken: book.loan_token,
110
+ collateralParams: book.collaterals.map((collateral) => ({
111
+ token: collateral.token,
112
+ lltv: collateral.lltv,
113
+ liquidationCursor: collateral.liquidation_cursor,
114
+ oracle: collateral.oracle,
115
+ })),
116
+ maturity: book.maturity,
117
+ rcfThreshold: book.rcf_threshold,
118
+ enterGate: book.enter_gate,
119
+ liquidatorGate: book.liquidator_gate,
120
+ });
121
+ // Comparison stays inside the try so a malformed advertised `market_id`
122
+ // (non-hex value) surfaces as a wrapped response error, not a raw TypeError.
123
+ matchesAdvertisedId = (0, morpho_ts_1.isHexEqual)(derivedMarketId, book.market_id);
124
+ }
125
+ catch (cause) {
126
+ throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API book market_id "${book.market_id}" could not be validated against its market params.`, { cause });
127
+ }
128
+ if (!matchesAdvertisedId) {
129
+ throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API book market_id "${book.market_id}" does not match the id "${derivedMarketId}" derived from its market params.`);
130
+ }
93
131
  return {
94
132
  marketId: book.market_id,
95
133
  chainId: book.chain_id,
@@ -104,6 +142,26 @@ function mapBookMarket(book) {
104
142
  bids: book.bids.map(mapPriceLevel),
105
143
  };
106
144
  }
145
+ /** @internal Maps a book market, binding its verified id to the requested market. */
146
+ function mapBoundBookMarket(book, requestedMarketId) {
147
+ const market = mapBookMarket(book);
148
+ if (!(0, morpho_ts_1.isHexEqual)(market.marketId, requestedMarketId)) {
149
+ throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API book market_id "${market.marketId}" does not match requested market "${requestedMarketId}".`);
150
+ }
151
+ return market;
152
+ }
153
+ /** @internal Maps listed book markets, binding each verified id to the requested market_ids filter when present. */
154
+ function mapBoundBooks(books, marketIds) {
155
+ return books.map((book) => {
156
+ const market = mapBookMarket(book);
157
+ if (marketIds != null &&
158
+ marketIds.length > 0 &&
159
+ !marketIds.some((marketId) => (0, morpho_ts_1.isHexEqual)(marketId, market.marketId))) {
160
+ throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API book market_id "${market.marketId}" is outside the requested market_ids filter.`);
161
+ }
162
+ return market;
163
+ });
164
+ }
107
165
  /** @internal Maps a collateral API payload to the SDK response shape. */
108
166
  function mapCollateral(collateral) {
109
167
  return {
@@ -220,7 +278,38 @@ function parseValidationResponse(response) {
220
278
  if (typeof rule !== "string") {
221
279
  throw new errors_js_1.InvalidMidnightApiResponseError('Midnight API validation issue is missing "rule".');
222
280
  }
223
- return { rule };
281
+ const details = record.details;
282
+ if (details == null)
283
+ return { rule };
284
+ if (rule === types_js_1.MempoolPayloadValidationRule.MinOfferAssetsUsd &&
285
+ isRecord(details)) {
286
+ const loanToken = details.loan_token;
287
+ const rawMinAssets = details.min_assets;
288
+ if (typeof loanToken === "string" &&
289
+ (0, viem_1.isAddress)(loanToken) &&
290
+ typeof rawMinAssets === "string" &&
291
+ rawMinAssets.length <= MAX_UINT256_DECIMAL_LENGTH &&
292
+ /^\d+$/.test(rawMinAssets)) {
293
+ const minAssets = BigInt(rawMinAssets);
294
+ if (minAssets <= viem_1.maxUint256) {
295
+ return {
296
+ rule,
297
+ details: {
298
+ type: "minOfferAssetsUsd",
299
+ loanToken,
300
+ minAssets,
301
+ },
302
+ };
303
+ }
304
+ }
305
+ }
306
+ return {
307
+ rule,
308
+ details: {
309
+ type: "unknown",
310
+ raw: details,
311
+ },
312
+ };
224
313
  });
225
314
  return {
226
315
  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
+ };
@@ -1,2 +1,2 @@
1
1
  /** @internal Installed Midnight SDK package version. */
2
- export declare const MIDNIGHT_SDK_VERSION = "1.2.1";
2
+ export declare const MIDNIGHT_SDK_VERSION = "1.3.1";
@@ -3,4 +3,4 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.MIDNIGHT_SDK_VERSION = void 0;
5
5
  /** @internal Installed Midnight SDK package version. */
6
- exports.MIDNIGHT_SDK_VERSION = "1.2.1";
6
+ exports.MIDNIGHT_SDK_VERSION = "1.3.1";
@@ -3,6 +3,6 @@ import type { DeploylessFetchParameters, MidnightCallParameters } from "./types.
3
3
  /** @internal Extracts viem call parameters from Midnight fetch inputs. */
4
4
  export declare const callParameters: (params: MidnightCallParameters) => MidnightCallParameters;
5
5
  /** @internal Returns the configured deployless mode, defaulting to enabled. */
6
- export declare const shouldUseDeployless: (params: DeploylessFetchParameters) => boolean | "force";
6
+ export declare const shouldUseDeployless: (params: DeploylessFetchParameters) => "force" | boolean;
7
7
  /** @internal Returns the RPC chain id and rejects configured-chain drift. */
8
8
  export declare const resolveChainId: (client: Client) => Promise<number>;
@@ -434,7 +434,7 @@ export declare namespace EcrecoverRatifierUtils {
434
434
  * console.log(EcrecoverRatifierUtils.treeTypeHash(0));
435
435
  * ```
436
436
  */
437
- function treeTypeHash(height: number): "0x270da1ebafc0f24637af3612fb8c3a1d828fcb56d3637c24e86dd006b12ca7f9" | "0x828b9cdf8326a1cf234328e4d5229546a98fb72ef73624f5b6b31538e555b96c" | "0xfcb7a3ca4094246b8185620c4cf025c93032b6f0384805aa3f22afe04290e982" | "0xcc97cb1955496a5269b5a7afca62ba694edcab26ba838a1adbd257931249de92" | "0xda3feb08db360ad9e09540132ff04d2b6a596fdaa4747892217aaa4c7c9bcc31" | "0x15bd6e2aa1a7a61614187ac16d2cbf8610c8f2f3c3d9eaa380ae7a501ee3cf06" | "0xb726cb7fab1a24c28213cbd482fa5a301f127fb25feb01da341919983a72711a" | "0xcea9cd557c6f821868ea287304199d0e0554af630bfa8fe36c64eb3bbacca418" | "0xf7dbde8234e8e345cec8fc0a8ac5909ee336b214882751ecd51e7b37df4f6cdd" | "0x5400a5d43d39e6bfe910af8cb84ac77bf501d310413769dffd62ccecda8b00c6" | "0x0754209b60d99d0822b3ecd5a970f9db09df9c8998a8441e24b81f06d6c76fee" | "0xf5d561d88647c3b38ed6636709d3166819fc66f8ed52a0daf4ae186387b4646c" | "0x5801c07a6c7df039ce00a7a2b8bd92aa1cf333c30b0bc3d78768590b6063d09e" | "0xc9da7190eaf4b14c7cb1c14f9898256c0adb6b1dc303afe79594dea64fe199c0" | "0xa47534c85ac57c583568465d40fd46683d2d558d8129fe1aca01e93023afca92" | "0xb1e841691fb54f4ef85e2ed9de45d610e57f49e1e6eb2510ceead16e447dd519" | "0x4fa4f16f09f0c36c7670449a4032073380d28a60071e12ee8874bb3e5a8318fc" | "0x817bbaac8bb863670f488b454cdd5d0990d9d81871a68e9df381c3c13d3f2ba2" | "0xc447f06079bddf4b011523c4bce119e9e90fdf937de4ee88f48010406560e9c1" | "0x1608d5eb56943c667c34b413f9f8a1c24a84ddfe1301a9c25487e638de1f5822" | "0x3a677100d2e855c24a62d1e9c365bff90d02287f066a07064843ca1ee70ea113";
437
+ function treeTypeHash(height: number): "0x0754209b60d99d0822b3ecd5a970f9db09df9c8998a8441e24b81f06d6c76fee" | "0x15bd6e2aa1a7a61614187ac16d2cbf8610c8f2f3c3d9eaa380ae7a501ee3cf06" | "0x1608d5eb56943c667c34b413f9f8a1c24a84ddfe1301a9c25487e638de1f5822" | "0x270da1ebafc0f24637af3612fb8c3a1d828fcb56d3637c24e86dd006b12ca7f9" | "0x3a677100d2e855c24a62d1e9c365bff90d02287f066a07064843ca1ee70ea113" | "0x4fa4f16f09f0c36c7670449a4032073380d28a60071e12ee8874bb3e5a8318fc" | "0x5400a5d43d39e6bfe910af8cb84ac77bf501d310413769dffd62ccecda8b00c6" | "0x5801c07a6c7df039ce00a7a2b8bd92aa1cf333c30b0bc3d78768590b6063d09e" | "0x817bbaac8bb863670f488b454cdd5d0990d9d81871a68e9df381c3c13d3f2ba2" | "0x828b9cdf8326a1cf234328e4d5229546a98fb72ef73624f5b6b31538e555b96c" | "0xa47534c85ac57c583568465d40fd46683d2d558d8129fe1aca01e93023afca92" | "0xb1e841691fb54f4ef85e2ed9de45d610e57f49e1e6eb2510ceead16e447dd519" | "0xb726cb7fab1a24c28213cbd482fa5a301f127fb25feb01da341919983a72711a" | "0xc447f06079bddf4b011523c4bce119e9e90fdf937de4ee88f48010406560e9c1" | "0xc9da7190eaf4b14c7cb1c14f9898256c0adb6b1dc303afe79594dea64fe199c0" | "0xcc97cb1955496a5269b5a7afca62ba694edcab26ba838a1adbd257931249de92" | "0xcea9cd557c6f821868ea287304199d0e0554af630bfa8fe36c64eb3bbacca418" | "0xda3feb08db360ad9e09540132ff04d2b6a596fdaa4747892217aaa4c7c9bcc31" | "0xf5d561d88647c3b38ed6636709d3166819fc66f8ed52a0daf4ae186387b4646c" | "0xf7dbde8234e8e345cec8fc0a8ac5909ee336b214882751ecd51e7b37df4f6cdd" | "0xfcb7a3ca4094246b8185620c4cf025c93032b6f0384805aa3f22afe04290e982";
438
438
  /**
439
439
  * Builds EcrecoverRatifier typed data for a tree-like input.
440
440
  *
@@ -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
  *
@@ -66,7 +67,7 @@ export declare class MidnightApi {
66
67
  * @param params.request - Optional fetch options forwarded to this request.
67
68
  * @returns Paginated books mapped to SDK camelCase fields.
68
69
  * @throws {MidnightApiError} when the API returns a non-2xx response.
69
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
70
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
70
71
  * @example
71
72
  * ```ts
72
73
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -91,7 +92,7 @@ export declare class MidnightApi {
91
92
  * @param params.request - Optional fetch options forwarded to this request.
92
93
  * @returns Book snapshot mapped to SDK camelCase fields.
93
94
  * @throws {MidnightApiError} when the API returns a non-2xx response.
94
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
95
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
95
96
  * @example
96
97
  * ```ts
97
98
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -319,7 +320,7 @@ export declare class MidnightApi {
319
320
  * @param params.cursor - Optional opaque pagination cursor from a previous response.
320
321
  * @returns Paginated books mapped to SDK camelCase fields.
321
322
  * @throws {MidnightApiError} when the API returns a non-2xx response.
322
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
323
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
323
324
  * @example
324
325
  * ```ts
325
326
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -339,7 +340,7 @@ export declare class MidnightApi {
339
340
  * @param params.depth - Optional maximum levels returned per side.
340
341
  * @returns Book snapshot mapped to SDK camelCase fields.
341
342
  * @throws {MidnightApiError} when the API returns a non-2xx response.
342
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
343
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
343
344
  * @example
344
345
  * ```ts
345
346
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -2,7 +2,8 @@ import { MathLib } from "@morpho-org/morpho-ts";
2
2
  import { InvalidMidnightApiResponseError } from "../errors.js";
3
3
  import { TickLib } from "../math/index.js";
4
4
  import { Payload } from "../signatures/Payload.js";
5
- import { buildBookPath, mapBookMarket, mapBoundTakeableOffers, mapPriceLevel, parseValidationResponse, requestMidnightApi, } from "./helpers.js";
5
+ import { buildBookPath, mapBoundBookMarket, mapBoundBooks, 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
  *
@@ -74,7 +75,7 @@ export class MidnightApi {
74
75
  * @param params.request - Optional fetch options forwarded to this request.
75
76
  * @returns Paginated books mapped to SDK camelCase fields.
76
77
  * @throws {MidnightApiError} when the API returns a non-2xx response.
77
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
78
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
78
79
  * @example
79
80
  * ```ts
80
81
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -105,7 +106,7 @@ export class MidnightApi {
105
106
  });
106
107
  return {
107
108
  cursor: response.cursor,
108
- data: response.data.map(mapBookMarket),
109
+ data: mapBoundBooks(response.data, input.marketIds),
109
110
  };
110
111
  }
111
112
  /**
@@ -120,7 +121,7 @@ export class MidnightApi {
120
121
  * @param params.request - Optional fetch options forwarded to this request.
121
122
  * @returns Book snapshot mapped to SDK camelCase fields.
122
123
  * @throws {MidnightApiError} when the API returns a non-2xx response.
123
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
124
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
124
125
  * @example
125
126
  * ```ts
126
127
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -142,7 +143,7 @@ export class MidnightApi {
142
143
  },
143
144
  });
144
145
  return {
145
- data: mapBookMarket(response.data),
146
+ data: mapBoundBookMarket(response.data, input.marketId),
146
147
  };
147
148
  }
148
149
  /**
@@ -520,7 +521,7 @@ export class MidnightApi {
520
521
  * @param params.cursor - Optional opaque pagination cursor from a previous response.
521
522
  * @returns Paginated books mapped to SDK camelCase fields.
522
523
  * @throws {MidnightApiError} when the API returns a non-2xx response.
523
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
524
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when a returned book's `market_id` does not match, or cannot be derived from, its own market params, or when a returned book falls outside the supplied `marketIds` filter.
524
525
  * @example
525
526
  * ```ts
526
527
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -545,7 +546,7 @@ export class MidnightApi {
545
546
  * @param params.depth - Optional maximum levels returned per side.
546
547
  * @returns Book snapshot mapped to SDK camelCase fields.
547
548
  * @throws {MidnightApiError} when the API returns a non-2xx response.
548
- * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON.
549
+ * @throws {InvalidMidnightApiResponseError} when the API success response is not JSON, when the returned book's `market_id` does not match, or cannot be derived from, its own market params, or when it differs from the requested `marketId`.
549
550
  * @example
550
551
  * ```ts
551
552
  * import { MidnightApi } from "@morpho-org/midnight-sdk/api";
@@ -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. */
@@ -8,8 +8,18 @@ export declare function buildBookPath(params: {
8
8
  readonly side?: MidnightApiBookSide;
9
9
  readonly suffix?: "quote" | "takeable-offers";
10
10
  }): string;
11
- /** @internal Maps a book market API payload to the SDK response shape. */
11
+ /**
12
+ * @internal Maps a book market API payload to the SDK response shape, rejecting any
13
+ * response whose advertised `market_id` cannot be derived from — or does not match —
14
+ * its own market params. Recomputing the id with `MarketUtils.toId` (mirroring the
15
+ * takeable-offers path) stops a hostile API from pairing a trusted id with foreign
16
+ * metadata; every book flows through here, so both bound paths reject the same substitution.
17
+ */
12
18
  export declare function mapBookMarket(book: ApiBookMarketResponse): MidnightApiBookMarket;
19
+ /** @internal Maps a book market, binding its verified id to the requested market. */
20
+ export declare function mapBoundBookMarket(book: ApiBookMarketResponse, requestedMarketId: Hash): MidnightApiBookMarket;
21
+ /** @internal Maps listed book markets, binding each verified id to the requested market_ids filter when present. */
22
+ export declare function mapBoundBooks(books: readonly ApiBookMarketResponse[], marketIds?: readonly Hash[]): MidnightApiBookMarket[];
13
23
  /** @internal Maps a collateral API payload to the SDK response shape. */
14
24
  export declare function mapCollateral(collateral: ApiCollateralResponse): MidnightApiCollateral;
15
25
  /** @internal Maps a price-level API payload to the SDK response shape. */
@@ -1,9 +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";
5
6
  import { MIDNIGHT_SDK_VERSION } from "./version.generated.js";
6
7
  const DEFAULT_MIDNIGHT_API_URL = new URL("/v0/midnight", BLUE_API_BASE_URL);
8
+ const MAX_UINT256_DECIMAL_LENGTH = maxUint256.toString().length;
7
9
  /** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
8
10
  export async function requestMidnightApi(params) {
9
11
  const baseUrl = new URL(params.baseUrl ?? DEFAULT_MIDNIGHT_API_URL);
@@ -78,8 +80,42 @@ export function buildBookPath(params) {
78
80
  ].filter((segment) => segment !== undefined);
79
81
  return segments.map(encodeURIComponent).join("/");
80
82
  }
81
- /** @internal Maps a book market API payload to the SDK response shape. */
83
+ /**
84
+ * @internal Maps a book market API payload to the SDK response shape, rejecting any
85
+ * response whose advertised `market_id` cannot be derived from — or does not match —
86
+ * its own market params. Recomputing the id with `MarketUtils.toId` (mirroring the
87
+ * takeable-offers path) stops a hostile API from pairing a trusted id with foreign
88
+ * metadata; every book flows through here, so both bound paths reject the same substitution.
89
+ */
82
90
  export function mapBookMarket(book) {
91
+ let derivedMarketId;
92
+ let matchesAdvertisedId;
93
+ try {
94
+ derivedMarketId = MarketUtils.toId({
95
+ chainId: book.chain_id,
96
+ midnight: book.midnight,
97
+ loanToken: book.loan_token,
98
+ collateralParams: book.collaterals.map((collateral) => ({
99
+ token: collateral.token,
100
+ lltv: collateral.lltv,
101
+ liquidationCursor: collateral.liquidation_cursor,
102
+ oracle: collateral.oracle,
103
+ })),
104
+ maturity: book.maturity,
105
+ rcfThreshold: book.rcf_threshold,
106
+ enterGate: book.enter_gate,
107
+ liquidatorGate: book.liquidator_gate,
108
+ });
109
+ // Comparison stays inside the try so a malformed advertised `market_id`
110
+ // (non-hex value) surfaces as a wrapped response error, not a raw TypeError.
111
+ matchesAdvertisedId = isHexEqual(derivedMarketId, book.market_id);
112
+ }
113
+ catch (cause) {
114
+ throw new InvalidMidnightApiResponseError(`Midnight API book market_id "${book.market_id}" could not be validated against its market params.`, { cause });
115
+ }
116
+ if (!matchesAdvertisedId) {
117
+ throw new InvalidMidnightApiResponseError(`Midnight API book market_id "${book.market_id}" does not match the id "${derivedMarketId}" derived from its market params.`);
118
+ }
83
119
  return {
84
120
  marketId: book.market_id,
85
121
  chainId: book.chain_id,
@@ -94,6 +130,26 @@ export function mapBookMarket(book) {
94
130
  bids: book.bids.map(mapPriceLevel),
95
131
  };
96
132
  }
133
+ /** @internal Maps a book market, binding its verified id to the requested market. */
134
+ export function mapBoundBookMarket(book, requestedMarketId) {
135
+ const market = mapBookMarket(book);
136
+ if (!isHexEqual(market.marketId, requestedMarketId)) {
137
+ throw new InvalidMidnightApiResponseError(`Midnight API book market_id "${market.marketId}" does not match requested market "${requestedMarketId}".`);
138
+ }
139
+ return market;
140
+ }
141
+ /** @internal Maps listed book markets, binding each verified id to the requested market_ids filter when present. */
142
+ export function mapBoundBooks(books, marketIds) {
143
+ return books.map((book) => {
144
+ const market = mapBookMarket(book);
145
+ if (marketIds != null &&
146
+ marketIds.length > 0 &&
147
+ !marketIds.some((marketId) => isHexEqual(marketId, market.marketId))) {
148
+ throw new InvalidMidnightApiResponseError(`Midnight API book market_id "${market.marketId}" is outside the requested market_ids filter.`);
149
+ }
150
+ return market;
151
+ });
152
+ }
97
153
  /** @internal Maps a collateral API payload to the SDK response shape. */
98
154
  export function mapCollateral(collateral) {
99
155
  return {
@@ -210,7 +266,38 @@ export function parseValidationResponse(response) {
210
266
  if (typeof rule !== "string") {
211
267
  throw new InvalidMidnightApiResponseError('Midnight API validation issue is missing "rule".');
212
268
  }
213
- return { rule };
269
+ const details = record.details;
270
+ if (details == null)
271
+ return { rule };
272
+ if (rule === MempoolPayloadValidationRule.MinOfferAssetsUsd &&
273
+ isRecord(details)) {
274
+ const loanToken = details.loan_token;
275
+ const rawMinAssets = details.min_assets;
276
+ if (typeof loanToken === "string" &&
277
+ isAddress(loanToken) &&
278
+ typeof rawMinAssets === "string" &&
279
+ rawMinAssets.length <= MAX_UINT256_DECIMAL_LENGTH &&
280
+ /^\d+$/.test(rawMinAssets)) {
281
+ const minAssets = BigInt(rawMinAssets);
282
+ if (minAssets <= maxUint256) {
283
+ return {
284
+ rule,
285
+ details: {
286
+ type: "minOfferAssetsUsd",
287
+ loanToken,
288
+ minAssets,
289
+ },
290
+ };
291
+ }
292
+ }
293
+ }
294
+ return {
295
+ rule,
296
+ details: {
297
+ type: "unknown",
298
+ raw: details,
299
+ },
300
+ };
214
301
  });
215
302
  return {
216
303
  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
+ };
@@ -1,2 +1,2 @@
1
1
  /** @internal Installed Midnight SDK package version. */
2
- export declare const MIDNIGHT_SDK_VERSION = "1.2.1";
2
+ export declare const MIDNIGHT_SDK_VERSION = "1.3.1";
@@ -1,3 +1,3 @@
1
1
  // Generated by scripts/release/generate-midnight-package-version.mjs. Do not edit.
2
2
  /** @internal Installed Midnight SDK package version. */
3
- export const MIDNIGHT_SDK_VERSION = "1.2.1";
3
+ export const MIDNIGHT_SDK_VERSION = "1.3.1";
@@ -3,6 +3,6 @@ import type { DeploylessFetchParameters, MidnightCallParameters } from "./types.
3
3
  /** @internal Extracts viem call parameters from Midnight fetch inputs. */
4
4
  export declare const callParameters: (params: MidnightCallParameters) => MidnightCallParameters;
5
5
  /** @internal Returns the configured deployless mode, defaulting to enabled. */
6
- export declare const shouldUseDeployless: (params: DeploylessFetchParameters) => boolean | "force";
6
+ export declare const shouldUseDeployless: (params: DeploylessFetchParameters) => "force" | boolean;
7
7
  /** @internal Returns the RPC chain id and rejects configured-chain drift. */
8
8
  export declare const resolveChainId: (client: Client) => Promise<number>;
@@ -434,7 +434,7 @@ export declare namespace EcrecoverRatifierUtils {
434
434
  * console.log(EcrecoverRatifierUtils.treeTypeHash(0));
435
435
  * ```
436
436
  */
437
- function treeTypeHash(height: number): "0x270da1ebafc0f24637af3612fb8c3a1d828fcb56d3637c24e86dd006b12ca7f9" | "0x828b9cdf8326a1cf234328e4d5229546a98fb72ef73624f5b6b31538e555b96c" | "0xfcb7a3ca4094246b8185620c4cf025c93032b6f0384805aa3f22afe04290e982" | "0xcc97cb1955496a5269b5a7afca62ba694edcab26ba838a1adbd257931249de92" | "0xda3feb08db360ad9e09540132ff04d2b6a596fdaa4747892217aaa4c7c9bcc31" | "0x15bd6e2aa1a7a61614187ac16d2cbf8610c8f2f3c3d9eaa380ae7a501ee3cf06" | "0xb726cb7fab1a24c28213cbd482fa5a301f127fb25feb01da341919983a72711a" | "0xcea9cd557c6f821868ea287304199d0e0554af630bfa8fe36c64eb3bbacca418" | "0xf7dbde8234e8e345cec8fc0a8ac5909ee336b214882751ecd51e7b37df4f6cdd" | "0x5400a5d43d39e6bfe910af8cb84ac77bf501d310413769dffd62ccecda8b00c6" | "0x0754209b60d99d0822b3ecd5a970f9db09df9c8998a8441e24b81f06d6c76fee" | "0xf5d561d88647c3b38ed6636709d3166819fc66f8ed52a0daf4ae186387b4646c" | "0x5801c07a6c7df039ce00a7a2b8bd92aa1cf333c30b0bc3d78768590b6063d09e" | "0xc9da7190eaf4b14c7cb1c14f9898256c0adb6b1dc303afe79594dea64fe199c0" | "0xa47534c85ac57c583568465d40fd46683d2d558d8129fe1aca01e93023afca92" | "0xb1e841691fb54f4ef85e2ed9de45d610e57f49e1e6eb2510ceead16e447dd519" | "0x4fa4f16f09f0c36c7670449a4032073380d28a60071e12ee8874bb3e5a8318fc" | "0x817bbaac8bb863670f488b454cdd5d0990d9d81871a68e9df381c3c13d3f2ba2" | "0xc447f06079bddf4b011523c4bce119e9e90fdf937de4ee88f48010406560e9c1" | "0x1608d5eb56943c667c34b413f9f8a1c24a84ddfe1301a9c25487e638de1f5822" | "0x3a677100d2e855c24a62d1e9c365bff90d02287f066a07064843ca1ee70ea113";
437
+ function treeTypeHash(height: number): "0x0754209b60d99d0822b3ecd5a970f9db09df9c8998a8441e24b81f06d6c76fee" | "0x15bd6e2aa1a7a61614187ac16d2cbf8610c8f2f3c3d9eaa380ae7a501ee3cf06" | "0x1608d5eb56943c667c34b413f9f8a1c24a84ddfe1301a9c25487e638de1f5822" | "0x270da1ebafc0f24637af3612fb8c3a1d828fcb56d3637c24e86dd006b12ca7f9" | "0x3a677100d2e855c24a62d1e9c365bff90d02287f066a07064843ca1ee70ea113" | "0x4fa4f16f09f0c36c7670449a4032073380d28a60071e12ee8874bb3e5a8318fc" | "0x5400a5d43d39e6bfe910af8cb84ac77bf501d310413769dffd62ccecda8b00c6" | "0x5801c07a6c7df039ce00a7a2b8bd92aa1cf333c30b0bc3d78768590b6063d09e" | "0x817bbaac8bb863670f488b454cdd5d0990d9d81871a68e9df381c3c13d3f2ba2" | "0x828b9cdf8326a1cf234328e4d5229546a98fb72ef73624f5b6b31538e555b96c" | "0xa47534c85ac57c583568465d40fd46683d2d558d8129fe1aca01e93023afca92" | "0xb1e841691fb54f4ef85e2ed9de45d610e57f49e1e6eb2510ceead16e447dd519" | "0xb726cb7fab1a24c28213cbd482fa5a301f127fb25feb01da341919983a72711a" | "0xc447f06079bddf4b011523c4bce119e9e90fdf937de4ee88f48010406560e9c1" | "0xc9da7190eaf4b14c7cb1c14f9898256c0adb6b1dc303afe79594dea64fe199c0" | "0xcc97cb1955496a5269b5a7afca62ba694edcab26ba838a1adbd257931249de92" | "0xcea9cd557c6f821868ea287304199d0e0554af630bfa8fe36c64eb3bbacca418" | "0xda3feb08db360ad9e09540132ff04d2b6a596fdaa4747892217aaa4c7c9bcc31" | "0xf5d561d88647c3b38ed6636709d3166819fc66f8ed52a0daf4ae186387b4646c" | "0xf7dbde8234e8e345cec8fc0a8ac5909ee336b214882751ecd51e7b37df4f6cdd" | "0xfcb7a3ca4094246b8185620c4cf025c93032b6f0384805aa3f22afe04290e982";
438
438
  /**
439
439
  * Builds EcrecoverRatifier typed data for a tree-like input.
440
440
  *
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.1",
4
+ "version": "1.3.1",
5
5
  "author": "Morpho Association <contact@morpho.org>",
6
6
  "contributors": [
7
7
  "Rubilmax <rmilon@gmail.com>"
@@ -47,12 +47,12 @@
47
47
  "viem": "^2.0.0"
48
48
  },
49
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.3"
50
+ "fast-check": "^4.9.0",
51
+ "typescript": "^7.0.2",
52
+ "viem": "^2.55.10",
53
+ "vitest": "^4.1.10",
54
+ "@morpho-org/morpho-ts": "^2.11.1",
55
+ "@morpho-org/test": "^2.10.0"
56
56
  },
57
57
  "scripts": {
58
58
  "prepublish": "$npm_execpath build",
@@ -61,7 +61,7 @@
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
63
  "generate:version": "node ../../scripts/release/generate-midnight-package-version.mjs",
64
- "test": "vitest --root ../.. --project midnight-sdk"
64
+ "test": "vitest --root ../.. --project midnight-sdk --project midnight-sdk-fork"
65
65
  },
66
66
  "types": "./lib/esm/index.d.ts"
67
67
  }