@morpho-org/midnight-sdk 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/api/MidnightApi.js +67 -3
- package/lib/cjs/api/helpers.d.ts +11 -1
- package/lib/cjs/api/helpers.js +48 -1
- package/lib/cjs/errors.d.ts +15 -0
- package/lib/cjs/errors.js +21 -1
- package/lib/cjs/fetch/Market.js +37 -2
- package/lib/cjs/fetch/utils.d.ts +1 -1
- package/lib/cjs/fetch/utils.js +9 -2
- package/lib/cjs/offers/Offer.d.ts +1 -1
- package/lib/cjs/offers/OfferUtils.d.ts +5 -5
- package/lib/cjs/offers/OfferUtils.js +26 -13
- package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +118 -0
- package/lib/cjs/signatures/EcrecoverRatifierUtils.js +149 -1
- package/lib/cjs/signatures/Group.js +5 -3
- package/lib/cjs/signatures/GroupUtils.d.ts +48 -0
- package/lib/cjs/signatures/GroupUtils.js +51 -0
- package/lib/cjs/signatures/RatifierUtils.js +14 -3
- package/lib/cjs/signatures/SetterRatifierUtils.d.ts +31 -0
- package/lib/cjs/signatures/SetterRatifierUtils.js +38 -0
- package/lib/cjs/signatures/Tree.js +10 -2
- package/lib/cjs/signatures/TreeUtils.d.ts +4 -1
- package/lib/cjs/signatures/TreeUtils.js +19 -6
- package/lib/cjs/signatures/eip712.d.ts +22 -0
- package/lib/cjs/signatures/eip712.js +26 -0
- package/lib/cjs/signatures/index.d.ts +1 -0
- package/lib/cjs/signatures/index.js +1 -0
- package/lib/esm/api/MidnightApi.js +68 -4
- package/lib/esm/api/helpers.d.ts +11 -1
- package/lib/esm/api/helpers.js +48 -2
- package/lib/esm/errors.d.ts +15 -0
- package/lib/esm/errors.js +19 -0
- package/lib/esm/fetch/Market.js +38 -3
- package/lib/esm/fetch/utils.d.ts +1 -1
- package/lib/esm/fetch/utils.js +9 -2
- package/lib/esm/offers/Offer.d.ts +1 -1
- package/lib/esm/offers/OfferUtils.d.ts +5 -5
- package/lib/esm/offers/OfferUtils.js +28 -15
- package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +118 -0
- package/lib/esm/signatures/EcrecoverRatifierUtils.js +151 -3
- package/lib/esm/signatures/Group.js +5 -3
- package/lib/esm/signatures/GroupUtils.d.ts +48 -0
- package/lib/esm/signatures/GroupUtils.js +51 -0
- package/lib/esm/signatures/RatifierUtils.js +15 -4
- package/lib/esm/signatures/SetterRatifierUtils.d.ts +31 -0
- package/lib/esm/signatures/SetterRatifierUtils.js +38 -0
- package/lib/esm/signatures/Tree.js +11 -3
- package/lib/esm/signatures/TreeUtils.d.ts +4 -1
- package/lib/esm/signatures/TreeUtils.js +19 -6
- package/lib/esm/signatures/eip712.d.ts +22 -0
- package/lib/esm/signatures/eip712.js +22 -0
- package/lib/esm/signatures/index.d.ts +1 -0
- package/lib/esm/signatures/index.js +1 -0
- package/package.json +8 -7
- package/src/index.ts +0 -19
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MidnightApi = void 0;
|
|
4
|
+
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
5
|
+
const errors_js_1 = require("../errors.js");
|
|
6
|
+
const index_js_1 = require("../math/index.js");
|
|
4
7
|
const Payload_js_1 = require("../signatures/Payload.js");
|
|
5
8
|
const helpers_js_1 = require("./helpers.js");
|
|
6
9
|
/**
|
|
@@ -220,7 +223,10 @@ class MidnightApi {
|
|
|
220
223
|
}),
|
|
221
224
|
});
|
|
222
225
|
return {
|
|
223
|
-
data:
|
|
226
|
+
data: (0, helpers_js_1.mapBoundTakeableOffers)(response.data, {
|
|
227
|
+
marketId: input.marketId,
|
|
228
|
+
side: input.side,
|
|
229
|
+
}),
|
|
224
230
|
};
|
|
225
231
|
}
|
|
226
232
|
/**
|
|
@@ -270,7 +276,61 @@ class MidnightApi {
|
|
|
270
276
|
assets: input.assets,
|
|
271
277
|
},
|
|
272
278
|
});
|
|
273
|
-
const takeableOffers = response.data.takeable_offers
|
|
279
|
+
const takeableOffers = (0, helpers_js_1.mapBoundTakeableOffers)(response.data.takeable_offers, {
|
|
280
|
+
marketId: input.marketId,
|
|
281
|
+
side: input.side,
|
|
282
|
+
});
|
|
283
|
+
const averageWorstPrice = "averageWorstPrice" in input && input.averageWorstPrice != null
|
|
284
|
+
? input.averageWorstPrice
|
|
285
|
+
: "slippage" in input && input.slippage != null
|
|
286
|
+
? response.data.average_worst_price
|
|
287
|
+
: undefined;
|
|
288
|
+
if (averageWorstPrice != null) {
|
|
289
|
+
const guard = BigInt(averageWorstPrice);
|
|
290
|
+
let filledUnits = 0n;
|
|
291
|
+
let weightedPrice = 0n;
|
|
292
|
+
if ("units" in input && input.units != null) {
|
|
293
|
+
let remainingUnits = BigInt(input.units);
|
|
294
|
+
for (const take of takeableOffers) {
|
|
295
|
+
if (remainingUnits === 0n)
|
|
296
|
+
break;
|
|
297
|
+
const price = index_js_1.TickLib.tickToPrice(take.offer.tick);
|
|
298
|
+
const filled = take.units < remainingUnits ? take.units : remainingUnits;
|
|
299
|
+
filledUnits += filled;
|
|
300
|
+
weightedPrice += filled * price;
|
|
301
|
+
remainingUnits -= filled;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
let remainingAssets = BigInt(input.assets);
|
|
306
|
+
for (const take of takeableOffers) {
|
|
307
|
+
if (remainingAssets === 0n)
|
|
308
|
+
break;
|
|
309
|
+
const price = index_js_1.TickLib.tickToPrice(take.offer.tick);
|
|
310
|
+
const takeAssets = input.side === "asks"
|
|
311
|
+
? morpho_ts_1.MathLib.mulDivUp(take.units, price, morpho_ts_1.MathLib.WAD)
|
|
312
|
+
: morpho_ts_1.MathLib.mulDivDown(take.units, price, morpho_ts_1.MathLib.WAD);
|
|
313
|
+
if (takeAssets === 0n)
|
|
314
|
+
continue;
|
|
315
|
+
const fillsEntireTake = takeAssets <= remainingAssets;
|
|
316
|
+
const filled = fillsEntireTake
|
|
317
|
+
? take.units
|
|
318
|
+
: morpho_ts_1.MathLib.mulDiv(remainingAssets, morpho_ts_1.MathLib.WAD, price, input.side === "asks" ? "Down" : "Up");
|
|
319
|
+
if (filled === 0n)
|
|
320
|
+
continue;
|
|
321
|
+
filledUnits += filled;
|
|
322
|
+
weightedPrice += filled * price;
|
|
323
|
+
remainingAssets = fillsEntireTake ? remainingAssets - takeAssets : 0n;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (filledUnits > 0n) {
|
|
327
|
+
const averagePrice = morpho_ts_1.MathLib.mulDivDown(weightedPrice, 1n, filledUnits);
|
|
328
|
+
const violatesGuard = input.side === "asks" ? averagePrice > guard : averagePrice < guard;
|
|
329
|
+
if (violatesGuard) {
|
|
330
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API quote takeable offers imply average price "${averagePrice}" outside average_worst_price guard "${guard}".`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
274
334
|
return {
|
|
275
335
|
data: {
|
|
276
336
|
averageBestPrice: response.data.average_best_price,
|
|
@@ -323,7 +383,11 @@ class MidnightApi {
|
|
|
323
383
|
});
|
|
324
384
|
return {
|
|
325
385
|
cursor: response.cursor,
|
|
326
|
-
data:
|
|
386
|
+
data: (0, helpers_js_1.mapBoundTakeableOffers)(response.data, {
|
|
387
|
+
maker: input.maker,
|
|
388
|
+
marketIds: input.marketIds,
|
|
389
|
+
groups: input.groups,
|
|
390
|
+
}),
|
|
327
391
|
};
|
|
328
392
|
}
|
|
329
393
|
/**
|
package/lib/cjs/api/helpers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Address, type Hash } from "viem";
|
|
2
2
|
import type { ApiBookMarketResponse, ApiCollateralResponse, ApiPriceLevelResponse, ApiRequestParams, ApiTakeableOfferResponse, MempoolPayloadValidationResult, MidnightApiBookMarket, MidnightApiBookSide, MidnightApiCollateral, MidnightApiPriceLevel, 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>;
|
|
@@ -16,5 +16,15 @@ export declare function mapCollateral(collateral: ApiCollateralResponse): Midnig
|
|
|
16
16
|
export declare function mapPriceLevel(level: ApiPriceLevelResponse): MidnightApiPriceLevel;
|
|
17
17
|
/** @internal Maps a takeable-offer API payload to the SDK response shape. */
|
|
18
18
|
export declare function mapTakeableOffer(takeableOffer: ApiTakeableOfferResponse): MidnightApiTake;
|
|
19
|
+
/** @internal API response context required for a takeable offer to be executable for the caller's request. */
|
|
20
|
+
export interface TakeableOfferContext {
|
|
21
|
+
readonly marketId?: Hash;
|
|
22
|
+
readonly side?: MidnightApiBookSide;
|
|
23
|
+
readonly maker?: Address;
|
|
24
|
+
readonly marketIds?: readonly Hash[];
|
|
25
|
+
readonly groups?: readonly Hash[];
|
|
26
|
+
}
|
|
27
|
+
/** @internal Maps, validates, and best-price-sorts API takeable offers. */
|
|
28
|
+
export declare function mapBoundTakeableOffers(takeableOffers: readonly ApiTakeableOfferResponse[], context: TakeableOfferContext): MidnightApiTake[];
|
|
19
29
|
/** @internal Parses the mempool validation response envelope. */
|
|
20
30
|
export declare function parseValidationResponse(response: unknown): MempoolPayloadValidationResult;
|
package/lib/cjs/api/helpers.js
CHANGED
|
@@ -6,13 +6,16 @@ exports.mapBookMarket = mapBookMarket;
|
|
|
6
6
|
exports.mapCollateral = mapCollateral;
|
|
7
7
|
exports.mapPriceLevel = mapPriceLevel;
|
|
8
8
|
exports.mapTakeableOffer = mapTakeableOffer;
|
|
9
|
+
exports.mapBoundTakeableOffers = mapBoundTakeableOffers;
|
|
9
10
|
exports.parseValidationResponse = parseValidationResponse;
|
|
10
11
|
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
12
|
+
const viem_1 = require("viem");
|
|
11
13
|
const errors_js_1 = require("../errors.js");
|
|
14
|
+
const index_js_1 = require("../market/index.js");
|
|
12
15
|
const DEFAULT_MIDNIGHT_API_URL = new URL("/v0/midnight", morpho_ts_1.BLUE_API_BASE_URL);
|
|
13
16
|
// Keep this literal in source so the browser ESM build does not import package.json
|
|
14
17
|
// through Node-only createRequire/module shims.
|
|
15
|
-
const MIDNIGHT_SDK_VERSION = "0.1
|
|
18
|
+
const MIDNIGHT_SDK_VERSION = "1.0.1";
|
|
16
19
|
/** @internal Sends one Midnight API request and maps non-2xx responses to SDK errors. */
|
|
17
20
|
async function requestMidnightApi(params) {
|
|
18
21
|
const baseUrl = new URL(params.baseUrl ?? DEFAULT_MIDNIGHT_API_URL);
|
|
@@ -162,6 +165,50 @@ function mapTakeableOffer(takeableOffer) {
|
|
|
162
165
|
ratifierData: takeableOffer.ratifier_data,
|
|
163
166
|
};
|
|
164
167
|
}
|
|
168
|
+
/** @internal Maps, validates, and best-price-sorts API takeable offers. */
|
|
169
|
+
function mapBoundTakeableOffers(takeableOffers, context) {
|
|
170
|
+
const mapped = takeableOffers.map((takeableOffer) => {
|
|
171
|
+
const take = mapTakeableOffer(takeableOffer);
|
|
172
|
+
const embeddedMarketId = index_js_1.MarketUtils.toId(take.offer.market);
|
|
173
|
+
if (!(0, morpho_ts_1.isHexEqual)(embeddedMarketId, take.marketId)) {
|
|
174
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API takeable offer market_id "${take.marketId}" does not match embedded offer market "${embeddedMarketId}".`);
|
|
175
|
+
}
|
|
176
|
+
if (context.marketId != null &&
|
|
177
|
+
!(0, morpho_ts_1.isHexEqual)(take.marketId, context.marketId)) {
|
|
178
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API takeable offer market_id "${take.marketId}" does not match requested market "${context.marketId}".`);
|
|
179
|
+
}
|
|
180
|
+
if (context.marketIds != null &&
|
|
181
|
+
context.marketIds.length > 0 &&
|
|
182
|
+
!context.marketIds.some((marketId) => (0, morpho_ts_1.isHexEqual)(marketId, take.marketId))) {
|
|
183
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API takeable offer market_id "${take.marketId}" is outside the requested market_ids filter.`);
|
|
184
|
+
}
|
|
185
|
+
if (context.side != null) {
|
|
186
|
+
const expectedBuy = context.side === "bids";
|
|
187
|
+
if (take.offer.buy !== expectedBuy) {
|
|
188
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API ${context.side} takeable offer returned offer.buy "${take.offer.buy}".`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (context.maker != null &&
|
|
192
|
+
!(0, viem_1.isAddressEqual)(take.offer.maker, context.maker)) {
|
|
193
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API takeable offer maker "${take.offer.maker}" does not match requested maker "${context.maker}".`);
|
|
194
|
+
}
|
|
195
|
+
if (context.groups != null &&
|
|
196
|
+
context.groups.length > 0 &&
|
|
197
|
+
!context.groups.some((group) => (0, morpho_ts_1.isHexEqual)(group, take.offer.group))) {
|
|
198
|
+
throw new errors_js_1.InvalidMidnightApiResponseError(`Midnight API takeable offer group "${take.offer.group}" is outside the requested groups filter.`);
|
|
199
|
+
}
|
|
200
|
+
return take;
|
|
201
|
+
});
|
|
202
|
+
if (context.side == null)
|
|
203
|
+
return mapped;
|
|
204
|
+
return [...mapped].sort((a, b) => {
|
|
205
|
+
if (a.offer.tick === b.offer.tick)
|
|
206
|
+
return 0;
|
|
207
|
+
if (context.side === "asks")
|
|
208
|
+
return a.offer.tick < b.offer.tick ? -1 : 1;
|
|
209
|
+
return a.offer.tick > b.offer.tick ? -1 : 1;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
165
212
|
/** @internal Parses the mempool validation response envelope. */
|
|
166
213
|
function parseValidationResponse(response) {
|
|
167
214
|
const parsedResponse = requireRecord(response, "validation response");
|
package/lib/cjs/errors.d.ts
CHANGED
|
@@ -277,6 +277,21 @@ export declare class InvalidTypedDataSignatureError extends Error {
|
|
|
277
277
|
readonly signer: Address;
|
|
278
278
|
constructor(signer: Address, cause?: unknown);
|
|
279
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Thrown when decoded Ecrecover ratifier data contains a non-canonical signature `v` value.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```ts
|
|
285
|
+
* import { InvalidEcrecoverSignatureVError } from "@morpho-org/midnight-sdk";
|
|
286
|
+
*
|
|
287
|
+
* throw new InvalidEcrecoverSignatureVError(29);
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
export declare class InvalidEcrecoverSignatureVError extends Error {
|
|
291
|
+
/** Invalid ECDSA recovery id. */
|
|
292
|
+
readonly v: number;
|
|
293
|
+
constructor(v: number);
|
|
294
|
+
}
|
|
280
295
|
/**
|
|
281
296
|
* Thrown when the Midnight API returns a non-2xx response.
|
|
282
297
|
*
|
package/lib/cjs/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvalidMidnightApiResponseError = exports.MidnightApiError = exports.InvalidTypedDataSignatureError = exports.MidnightMempoolValidationError = exports.ChainIdMismatchError = exports.InvalidTreeError = exports.InvalidTreeHeightError = exports.PayloadDecodeError = exports.InvalidOfferParameterError = exports.UnknownCollateralIndexError = exports.InvalidMarketParameterError = exports.InvalidPositionAccrualStateError = exports.InvalidPositionLossFactorError = exports.InvalidPositionAccrualTimestampError = exports.SettlementFeeExceedsPriceError = exports.InvalidTickSpacingError = exports.PriceGreaterThanOneError = exports.TickOutOfRangeError = exports.InvalidOfferGroupError = void 0;
|
|
3
|
+
exports.InvalidMidnightApiResponseError = exports.MidnightApiError = exports.InvalidEcrecoverSignatureVError = exports.InvalidTypedDataSignatureError = exports.MidnightMempoolValidationError = exports.ChainIdMismatchError = exports.InvalidTreeError = exports.InvalidTreeHeightError = exports.PayloadDecodeError = exports.InvalidOfferParameterError = exports.UnknownCollateralIndexError = exports.InvalidMarketParameterError = exports.InvalidPositionAccrualStateError = exports.InvalidPositionLossFactorError = exports.InvalidPositionAccrualTimestampError = exports.SettlementFeeExceedsPriceError = exports.InvalidTickSpacingError = exports.PriceGreaterThanOneError = exports.TickOutOfRangeError = exports.InvalidOfferGroupError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Thrown when a Midnight offer group violates protocol-level group mechanics.
|
|
6
6
|
*
|
|
@@ -345,6 +345,26 @@ class InvalidTypedDataSignatureError extends Error {
|
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
exports.InvalidTypedDataSignatureError = InvalidTypedDataSignatureError;
|
|
348
|
+
/**
|
|
349
|
+
* Thrown when decoded Ecrecover ratifier data contains a non-canonical signature `v` value.
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```ts
|
|
353
|
+
* import { InvalidEcrecoverSignatureVError } from "@morpho-org/midnight-sdk";
|
|
354
|
+
*
|
|
355
|
+
* throw new InvalidEcrecoverSignatureVError(29);
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
class InvalidEcrecoverSignatureVError extends Error {
|
|
359
|
+
/** Invalid ECDSA recovery id. */
|
|
360
|
+
v;
|
|
361
|
+
constructor(v) {
|
|
362
|
+
super(`Ecrecover signature v "${v}" is invalid. Use canonical Ethereum v 27 or 28.`);
|
|
363
|
+
this.name = "InvalidEcrecoverSignatureVError";
|
|
364
|
+
this.v = v;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
exports.InvalidEcrecoverSignatureVError = InvalidEcrecoverSignatureVError;
|
|
348
368
|
/**
|
|
349
369
|
* Thrown when the Midnight API returns a non-2xx response.
|
|
350
370
|
*
|
package/lib/cjs/fetch/Market.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.fetchMarket = fetchMarket;
|
|
|
5
5
|
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
6
6
|
const actions_1 = require("viem/actions");
|
|
7
7
|
const abis_js_1 = require("../abis.js");
|
|
8
|
+
const errors_js_1 = require("../errors.js");
|
|
8
9
|
const index_js_1 = require("../market/index.js");
|
|
9
10
|
const utils_js_1 = require("./utils.js");
|
|
10
11
|
/**
|
|
@@ -45,7 +46,11 @@ async function fetchMarketParams(client, params) {
|
|
|
45
46
|
functionName: "toMarket",
|
|
46
47
|
args: [params.marketId],
|
|
47
48
|
});
|
|
48
|
-
return
|
|
49
|
+
return normalizeFetchedMarketParams(market, {
|
|
50
|
+
marketId: params.marketId,
|
|
51
|
+
chainId,
|
|
52
|
+
midnight,
|
|
53
|
+
});
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
51
56
|
* Fetches a hydrated market by id.
|
|
@@ -96,7 +101,11 @@ async function fetchMarket(client, params) {
|
|
|
96
101
|
]);
|
|
97
102
|
const [totalUnits, lossFactor, withdrawable, continuousFeeCredit, settlementFeeCbps0, settlementFeeCbps1, settlementFeeCbps2, settlementFeeCbps3, settlementFeeCbps4, settlementFeeCbps5, settlementFeeCbps6, continuousFee, tickSpacing,] = state;
|
|
98
103
|
return new index_js_1.Market({
|
|
99
|
-
params:
|
|
104
|
+
params: normalizeFetchedMarketParams(market, {
|
|
105
|
+
marketId: params.marketId,
|
|
106
|
+
chainId,
|
|
107
|
+
midnight,
|
|
108
|
+
}),
|
|
100
109
|
totalUnits,
|
|
101
110
|
lossFactor,
|
|
102
111
|
withdrawable,
|
|
@@ -114,3 +123,29 @@ async function fetchMarket(client, params) {
|
|
|
114
123
|
tickSpacing,
|
|
115
124
|
});
|
|
116
125
|
}
|
|
126
|
+
function normalizeFetchedMarketParams(market, expected) {
|
|
127
|
+
const marketParams = new index_js_1.MarketParams(market);
|
|
128
|
+
if (marketParams.chainId !== BigInt(expected.chainId)) {
|
|
129
|
+
throw new errors_js_1.InvalidMarketParameterError({
|
|
130
|
+
parameter: "chainId",
|
|
131
|
+
value: marketParams.chainId,
|
|
132
|
+
instruction: `Fetched market must use client chain id "${expected.chainId}".`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (marketParams.midnight.toLowerCase() !== expected.midnight.toLowerCase()) {
|
|
136
|
+
throw new errors_js_1.InvalidMarketParameterError({
|
|
137
|
+
parameter: "midnight",
|
|
138
|
+
value: marketParams.midnight,
|
|
139
|
+
instruction: `Fetched market must use Midnight contract "${expected.midnight}".`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const actualMarketId = index_js_1.MarketUtils.toId(marketParams);
|
|
143
|
+
if (actualMarketId.toLowerCase() !== expected.marketId.toLowerCase()) {
|
|
144
|
+
throw new errors_js_1.InvalidMarketParameterError({
|
|
145
|
+
parameter: "marketId",
|
|
146
|
+
value: actualMarketId,
|
|
147
|
+
instruction: `Fetched market must match requested market id "${expected.marketId}".`,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return marketParams;
|
|
151
|
+
}
|
package/lib/cjs/fetch/utils.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ import type { DeploylessFetchParameters, MidnightCallParameters } from "./types.
|
|
|
4
4
|
export declare const callParameters: (params: MidnightCallParameters) => MidnightCallParameters;
|
|
5
5
|
/** @internal Returns the configured deployless mode, defaulting to enabled. */
|
|
6
6
|
export declare const shouldUseDeployless: (params: DeploylessFetchParameters) => boolean | "force";
|
|
7
|
-
/** @internal Returns the
|
|
7
|
+
/** @internal Returns the RPC chain id and rejects configured-chain drift. */
|
|
8
8
|
export declare const resolveChainId: (client: Client) => Promise<number>;
|
package/lib/cjs/fetch/utils.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveChainId = exports.shouldUseDeployless = exports.callParameters = void 0;
|
|
4
4
|
const actions_1 = require("viem/actions");
|
|
5
|
+
const errors_js_1 = require("../errors.js");
|
|
5
6
|
/** @internal Extracts viem call parameters from Midnight fetch inputs. */
|
|
6
7
|
const callParameters = (params) => ({
|
|
7
8
|
account: params.account,
|
|
@@ -13,6 +14,12 @@ exports.callParameters = callParameters;
|
|
|
13
14
|
/** @internal Returns the configured deployless mode, defaulting to enabled. */
|
|
14
15
|
const shouldUseDeployless = (params) => params.deployless ?? true;
|
|
15
16
|
exports.shouldUseDeployless = shouldUseDeployless;
|
|
16
|
-
/** @internal Returns the
|
|
17
|
-
const resolveChainId = async (client) =>
|
|
17
|
+
/** @internal Returns the RPC chain id and rejects configured-chain drift. */
|
|
18
|
+
const resolveChainId = async (client) => {
|
|
19
|
+
const rpcChainId = await (0, actions_1.getChainId)(client);
|
|
20
|
+
if (client.chain?.id != null && client.chain.id !== rpcChainId) {
|
|
21
|
+
throw new errors_js_1.ChainIdMismatchError(client.chain.id, BigInt(rpcChainId));
|
|
22
|
+
}
|
|
23
|
+
return rpcChainId;
|
|
24
|
+
};
|
|
18
25
|
exports.resolveChainId = resolveChainId;
|
|
@@ -721,7 +721,7 @@ export interface BuildOfferParams {
|
|
|
721
721
|
readonly maxUnits?: BigIntish;
|
|
722
722
|
/** Maximum buyer or seller assets; defaults to zero. Exactly one of `maxUnits` and `maxAssets` must be non-zero. */
|
|
723
723
|
readonly maxAssets?: BigIntish;
|
|
724
|
-
/** Maximum market continuous fee accepted by this offer; defaults to
|
|
724
|
+
/** Maximum market continuous fee accepted by this offer; defaults to zero. */
|
|
725
725
|
readonly continuousFeeCap?: BigIntish;
|
|
726
726
|
/** Offer start timestamp; defaults to zero. */
|
|
727
727
|
readonly start?: BigIntish;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type BigIntish } from "@morpho-org/morpho-ts";
|
|
2
|
-
import type
|
|
2
|
+
import { type Address, type Hash } from "viem";
|
|
3
3
|
import { type BuildOfferParams, type IOffer, Offer, type OfferStruct } from "./Offer.js";
|
|
4
4
|
/**
|
|
5
5
|
* Object-compatible helpers for Midnight offer construction, grouping, and
|
|
@@ -280,8 +280,8 @@ export declare namespace OfferUtils {
|
|
|
280
280
|
* Validates and normalizes the maximum continuous fee an offer accepts.
|
|
281
281
|
*
|
|
282
282
|
* Use this before `Offer.create` when a maker UI exposes fee tolerance.
|
|
283
|
-
* `Offer.create` calls it internally and defaults omitted values to
|
|
284
|
-
*
|
|
283
|
+
* `Offer.create` calls it internally and defaults omitted values to zero so
|
|
284
|
+
* fresh offers fail closed unless the maker explicitly accepts a fee cap.
|
|
285
285
|
*
|
|
286
286
|
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer.
|
|
287
287
|
* @returns Normalized continuous fee cap.
|
|
@@ -339,7 +339,7 @@ export declare namespace OfferUtils {
|
|
|
339
339
|
* @param params.tickSpacing - Optional market tick spacing; defaults to `DEFAULT_TICK_SPACING`.
|
|
340
340
|
* @param params.maxUnits - Optional unit cap; defaults to zero.
|
|
341
341
|
* @param params.maxAssets - Optional buyer or seller asset cap; defaults to zero.
|
|
342
|
-
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer; defaults to
|
|
342
|
+
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer; defaults to zero.
|
|
343
343
|
* @param params.start - Optional offer start timestamp; defaults to zero.
|
|
344
344
|
* @param params.expiry - Offer expiry timestamp.
|
|
345
345
|
* @param params.receiverIfMakerIsSeller - Optional receiver used when maker is seller.
|
|
@@ -620,7 +620,7 @@ export declare namespace OfferUtils {
|
|
|
620
620
|
* ```
|
|
621
621
|
*/
|
|
622
622
|
function getConsumableUnits(params: {
|
|
623
|
-
readonly offer: Pick<IOffer, "market" | "buy" | "tick" | "maxUnits" | "maxAssets" | "continuousFeeCap">;
|
|
623
|
+
readonly offer: Pick<IOffer, "market" | "buy" | "start" | "expiry" | "tick" | "maxUnits" | "maxAssets" | "continuousFeeCap">;
|
|
624
624
|
readonly consumed: BigIntish;
|
|
625
625
|
readonly timestamp: BigIntish;
|
|
626
626
|
}): bigint;
|
|
@@ -8,7 +8,6 @@ const errors_js_1 = require("../errors.js");
|
|
|
8
8
|
const index_js_1 = require("../market/index.js");
|
|
9
9
|
const index_js_2 = require("../math/index.js");
|
|
10
10
|
const Offer_js_1 = require("./Offer.js");
|
|
11
|
-
const comparableHex = (value) => value.toLowerCase();
|
|
12
11
|
const offerHashParams = [
|
|
13
12
|
{ name: "typehash", type: "bytes32" },
|
|
14
13
|
{ name: "marketHash", type: "bytes32" },
|
|
@@ -417,8 +416,8 @@ var OfferUtils;
|
|
|
417
416
|
* Validates and normalizes the maximum continuous fee an offer accepts.
|
|
418
417
|
*
|
|
419
418
|
* Use this before `Offer.create` when a maker UI exposes fee tolerance.
|
|
420
|
-
* `Offer.create` calls it internally and defaults omitted values to
|
|
421
|
-
*
|
|
419
|
+
* `Offer.create` calls it internally and defaults omitted values to zero so
|
|
420
|
+
* fresh offers fail closed unless the maker explicitly accepts a fee cap.
|
|
422
421
|
*
|
|
423
422
|
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer.
|
|
424
423
|
* @returns Normalized continuous fee cap.
|
|
@@ -432,7 +431,7 @@ var OfferUtils;
|
|
|
432
431
|
* ```
|
|
433
432
|
*/
|
|
434
433
|
function validateContinuousFeeCap(params) {
|
|
435
|
-
const continuousFeeCap = BigInt(params.continuousFeeCap ??
|
|
434
|
+
const continuousFeeCap = BigInt(params.continuousFeeCap ?? 0n);
|
|
436
435
|
if (continuousFeeCap < 0n) {
|
|
437
436
|
throw new errors_js_1.InvalidOfferParameterError({
|
|
438
437
|
parameter: "continuousFeeCap",
|
|
@@ -491,7 +490,7 @@ var OfferUtils;
|
|
|
491
490
|
* @param params.tickSpacing - Optional market tick spacing; defaults to `DEFAULT_TICK_SPACING`.
|
|
492
491
|
* @param params.maxUnits - Optional unit cap; defaults to zero.
|
|
493
492
|
* @param params.maxAssets - Optional buyer or seller asset cap; defaults to zero.
|
|
494
|
-
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer; defaults to
|
|
493
|
+
* @param params.continuousFeeCap - Optional maximum market continuous fee accepted by this offer; defaults to zero.
|
|
495
494
|
* @param params.start - Optional offer start timestamp; defaults to zero.
|
|
496
495
|
* @param params.expiry - Offer expiry timestamp.
|
|
497
496
|
* @param params.receiverIfMakerIsSeller - Optional receiver used when maker is seller.
|
|
@@ -582,13 +581,15 @@ var OfferUtils;
|
|
|
582
581
|
}
|
|
583
582
|
const offers = offerInputs.map((offer) => Offer_js_1.Offer.from(offer));
|
|
584
583
|
const first = offers[0];
|
|
585
|
-
const expectedMaker =
|
|
584
|
+
const expectedMaker = first.maker;
|
|
586
585
|
const expectedBuy = first.buy;
|
|
587
|
-
const expectedLoanToken =
|
|
586
|
+
const expectedLoanToken = index_js_1.MarketParams.from(first.market).loanToken;
|
|
587
|
+
const expectedChainId = index_js_1.MarketParams.from(first.market).chainId;
|
|
588
|
+
const expectedMidnight = index_js_1.MarketParams.from(first.market).midnight;
|
|
588
589
|
const expectedMaxUnits = first.maxUnits;
|
|
589
590
|
const expectedMaxAssets = first.maxAssets;
|
|
590
591
|
for (const offer of offers) {
|
|
591
|
-
if (
|
|
592
|
+
if (!(0, viem_1.isAddressEqual)(offer.maker, expectedMaker)) {
|
|
592
593
|
throw new errors_js_1.InvalidOfferGroupError("All offers in a group must use the same maker.");
|
|
593
594
|
}
|
|
594
595
|
if (offer.buy !== expectedBuy) {
|
|
@@ -601,17 +602,21 @@ var OfferUtils;
|
|
|
601
602
|
(offer.maxAssets === 0n) === (offer.maxUnits === 0n)) {
|
|
602
603
|
throw new errors_js_1.InvalidOfferGroupError("Every offer must set exactly one non-zero uint128 cap.");
|
|
603
604
|
}
|
|
604
|
-
if (
|
|
605
|
-
expectedLoanToken) {
|
|
605
|
+
if (!(0, viem_1.isAddressEqual)(index_js_1.MarketParams.from(offer.market).loanToken, expectedLoanToken)) {
|
|
606
606
|
throw new errors_js_1.InvalidOfferGroupError("All offers in a group must use the same loan token.");
|
|
607
607
|
}
|
|
608
|
+
if (index_js_1.MarketParams.from(offer.market).chainId !== expectedChainId) {
|
|
609
|
+
throw new errors_js_1.InvalidOfferGroupError("All offers in a group must use the same chain id.");
|
|
610
|
+
}
|
|
611
|
+
if (!(0, viem_1.isAddressEqual)(index_js_1.MarketParams.from(offer.market).midnight, expectedMidnight)) {
|
|
612
|
+
throw new errors_js_1.InvalidOfferGroupError("All offers in a group must use the same Midnight contract.");
|
|
613
|
+
}
|
|
608
614
|
if (offer.maxUnits !== expectedMaxUnits ||
|
|
609
615
|
offer.maxAssets !== expectedMaxAssets) {
|
|
610
616
|
throw new errors_js_1.InvalidOfferGroupError("All offers in a group must use the same cap mode and value.");
|
|
611
617
|
}
|
|
612
618
|
if (offer.buy &&
|
|
613
|
-
|
|
614
|
-
comparableHex(viem_1.zeroAddress)) {
|
|
619
|
+
!(0, viem_1.isAddressEqual)(offer.receiverIfMakerIsSeller, viem_1.zeroAddress)) {
|
|
615
620
|
throw new errors_js_1.InvalidOfferGroupError("Buy offers must use the zero address as receiverIfMakerIsSeller.");
|
|
616
621
|
}
|
|
617
622
|
}
|
|
@@ -837,10 +842,16 @@ var OfferUtils;
|
|
|
837
842
|
function getConsumableUnits(params) {
|
|
838
843
|
const offer = params.offer;
|
|
839
844
|
const consumed = BigInt(params.consumed);
|
|
845
|
+
const timestamp = BigInt(params.timestamp);
|
|
846
|
+
const start = BigInt(offer.start);
|
|
847
|
+
const expiry = BigInt(offer.expiry);
|
|
840
848
|
const maxUnits = BigInt(offer.maxUnits);
|
|
841
849
|
const maxAssets = BigInt(offer.maxAssets);
|
|
842
850
|
const continuousFeeCap = BigInt(offer.continuousFeeCap);
|
|
843
851
|
(0, morpho_ts_1.assertNonNegative)("consumed", consumed);
|
|
852
|
+
(0, morpho_ts_1.assertNonNegative)("timestamp", timestamp);
|
|
853
|
+
(0, morpho_ts_1.assertNonNegative)("offer.start", start);
|
|
854
|
+
(0, morpho_ts_1.assertNonNegative)("offer.expiry", expiry);
|
|
844
855
|
(0, morpho_ts_1.assertNonNegative)("offer.maxUnits", maxUnits);
|
|
845
856
|
(0, morpho_ts_1.assertNonNegative)("offer.maxAssets", maxAssets);
|
|
846
857
|
(0, morpho_ts_1.assertNonNegative)("offer.continuousFeeCap", continuousFeeCap);
|
|
@@ -853,12 +864,14 @@ var OfferUtils;
|
|
|
853
864
|
});
|
|
854
865
|
}
|
|
855
866
|
const market = index_js_1.Market.from(offer.market);
|
|
867
|
+
if (timestamp < start || timestamp > expiry)
|
|
868
|
+
return 0n;
|
|
856
869
|
if (continuousFeeCap < BigInt(market.continuousFee))
|
|
857
870
|
return 0n;
|
|
858
871
|
if (maxUnits > 0n)
|
|
859
872
|
return morpho_ts_1.MathLib.zeroFloorSub(maxUnits, consumed);
|
|
860
873
|
const remainingAssets = morpho_ts_1.MathLib.zeroFloorSub(maxAssets, consumed);
|
|
861
|
-
const settlementFee = market.getSettlementFee(market.timeToMaturity(
|
|
874
|
+
const settlementFee = market.getSettlementFee(market.timeToMaturity(timestamp));
|
|
862
875
|
if (!offer.buy) {
|
|
863
876
|
const { sellerPrice } = index_js_2.TakeAmountsLib.prices({
|
|
864
877
|
offer,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type BigIntish } from "@morpho-org/morpho-ts";
|
|
2
2
|
import { type Account, type Address, type Chain, type Client, type Hash, type Hex, type Signature, type Transport } from "viem";
|
|
3
|
+
import { type IOffer } from "../offers/index.js";
|
|
3
4
|
import type { Payload } from "./Payload.js";
|
|
4
5
|
import { type RatifierTreeInput, type TreeProof } from "./TreeUtils.js";
|
|
5
6
|
declare const typedDataTypes: {
|
|
@@ -365,6 +366,40 @@ export interface EcrecoverRatifierDataParams {
|
|
|
365
366
|
/** Ecrecover signature for the tree root. */
|
|
366
367
|
readonly signature: EcrecoverSignatureInput;
|
|
367
368
|
}
|
|
369
|
+
/** Parameters for reconstructing an EcrecoverRatifier digest from decoded ratifier data fields. */
|
|
370
|
+
export interface EcrecoverRatifierRootDigestParams {
|
|
371
|
+
/** Observed EIP-155 chain id from the log or execution context. Must match `offer.market.chainId`. */
|
|
372
|
+
readonly chainId: BigIntish;
|
|
373
|
+
/** Offer whose ratifier address and market chain id define the EIP-712 domain. */
|
|
374
|
+
readonly offer: IOffer;
|
|
375
|
+
/** Merkle root embedded in the ratifier data. */
|
|
376
|
+
readonly root: Hash;
|
|
377
|
+
/** Number of sibling hashes in the Merkle proof. */
|
|
378
|
+
readonly proofLength: number;
|
|
379
|
+
}
|
|
380
|
+
/** Parameters for reconstructing an EcrecoverRatifier digest from encoded ratifier data. */
|
|
381
|
+
export interface EcrecoverRatifierDataDigestParams {
|
|
382
|
+
/** Observed EIP-155 chain id from the log or execution context. Must match `offer.market.chainId`. */
|
|
383
|
+
readonly chainId: BigIntish;
|
|
384
|
+
/** Offer carried by the payload item. */
|
|
385
|
+
readonly offer: IOffer;
|
|
386
|
+
/** ABI-encoded Ecrecover ratifier data carried by the payload item. */
|
|
387
|
+
readonly ratifierData: Hex;
|
|
388
|
+
}
|
|
389
|
+
/** Parameters for locally verifying Ecrecover ratifier data attached to one payload item. */
|
|
390
|
+
export interface EcrecoverRatifierDataVerificationParams {
|
|
391
|
+
/** Observed EIP-155 chain id from the log or execution context. Must match `offer.market.chainId`. */
|
|
392
|
+
readonly chainId: BigIntish;
|
|
393
|
+
/** Offer carried by the payload item. */
|
|
394
|
+
readonly offer: IOffer;
|
|
395
|
+
/** ABI-encoded Ecrecover ratifier data carried by the payload item. */
|
|
396
|
+
readonly ratifierData: Hex;
|
|
397
|
+
}
|
|
398
|
+
/** Decoded Ecrecover ratifier data after local proof verification and signature recovery. */
|
|
399
|
+
export interface VerifiedEcrecoverRatifierData extends DecodedEcrecoverRatifierData {
|
|
400
|
+
/** Signer recovered from the Ecrecover typed-data digest. */
|
|
401
|
+
readonly signer: Address;
|
|
402
|
+
}
|
|
368
403
|
/**
|
|
369
404
|
* EcrecoverRatifier-specific pure utilities.
|
|
370
405
|
*
|
|
@@ -501,6 +536,89 @@ export declare namespace EcrecoverRatifierUtils {
|
|
|
501
536
|
* ```
|
|
502
537
|
*/
|
|
503
538
|
function digest(params: EcrecoverRatifierTypedDataParams): `0x${string}`;
|
|
539
|
+
/**
|
|
540
|
+
* Builds the EcrecoverRatifier digest from a payload offer, root, and proof height.
|
|
541
|
+
*
|
|
542
|
+
* Use this on the take-side or in indexers after decoding ratifier data, when
|
|
543
|
+
* the original full tree is not available but the payload item includes the
|
|
544
|
+
* offer and proof metadata needed to reconstruct the signed digest. Pass the
|
|
545
|
+
* observed log or execution chain id so cross-chain-spoofed payloads are
|
|
546
|
+
* rejected before signature recovery.
|
|
547
|
+
*
|
|
548
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
549
|
+
* @param params.offer - Offer carried by the payload item.
|
|
550
|
+
* @param params.root - Merkle root embedded in the ratifier data.
|
|
551
|
+
* @param params.proofLength - Number of sibling hashes in the Merkle proof.
|
|
552
|
+
* @returns EIP-712 digest signed by the maker or authorized signer.
|
|
553
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
554
|
+
* @throws {InvalidTreeHeightError} when `proofLength` exceeds 20.
|
|
555
|
+
* @example
|
|
556
|
+
* ```ts
|
|
557
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
558
|
+
* import { zeroHash } from "viem";
|
|
559
|
+
*
|
|
560
|
+
* const digest = EcrecoverRatifierUtils.digestForRoot({
|
|
561
|
+
* chainId: 8453n,
|
|
562
|
+
* offer,
|
|
563
|
+
* root: zeroHash,
|
|
564
|
+
* proofLength: 0,
|
|
565
|
+
* });
|
|
566
|
+
* console.log(digest);
|
|
567
|
+
* ```
|
|
568
|
+
*/
|
|
569
|
+
function digestForRoot(params: EcrecoverRatifierRootDigestParams): Hash;
|
|
570
|
+
/**
|
|
571
|
+
* Builds the EcrecoverRatifier digest from one payload item's encoded ratifier data.
|
|
572
|
+
*
|
|
573
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
574
|
+
* @param params.offer - Offer carried by the payload item.
|
|
575
|
+
* @param params.ratifierData - ABI-encoded Ecrecover ratifier data.
|
|
576
|
+
* @returns EIP-712 digest signed by the maker or authorized signer.
|
|
577
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
578
|
+
* @throws {InvalidTreeHeightError} when the proof height exceeds 20.
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
582
|
+
*
|
|
583
|
+
* const digest = EcrecoverRatifierUtils.digestRatifierData({
|
|
584
|
+
* chainId: 8453n,
|
|
585
|
+
* offer,
|
|
586
|
+
* ratifierData,
|
|
587
|
+
* });
|
|
588
|
+
* console.log(digest);
|
|
589
|
+
* ```
|
|
590
|
+
*/
|
|
591
|
+
function digestRatifierData(params: EcrecoverRatifierDataDigestParams): Hash;
|
|
592
|
+
/**
|
|
593
|
+
* Verifies an Ecrecover ratifier-data proof and recovers its signer.
|
|
594
|
+
*
|
|
595
|
+
* This helper intentionally does not check `Midnight.isAuthorized` or
|
|
596
|
+
* `EcrecoverRatifier.isRootCanceled` state. Consumers must query both at the
|
|
597
|
+
* observed block before treating a recovered item as executable: the returned
|
|
598
|
+
* signer must be the maker or authorized by the maker, the offer ratifier must
|
|
599
|
+
* be authorized by the maker, and `isRootCanceled(maker, root)` must be false.
|
|
600
|
+
*
|
|
601
|
+
* @param params.chainId - Observed EIP-155 chain id from the log or execution context.
|
|
602
|
+
* @param params.offer - Offer carried by the payload item.
|
|
603
|
+
* @param params.ratifierData - ABI-encoded Ecrecover ratifier data.
|
|
604
|
+
* @returns Decoded ratifier data plus recovered signer.
|
|
605
|
+
* @throws {ChainIdMismatchError} when `params.chainId` does not match `offer.market.chainId`.
|
|
606
|
+
* @throws {InvalidEcrecoverSignatureVError} when the decoded signature `v` is not 27 or 28.
|
|
607
|
+
* @throws {InvalidTreeError} when the proof does not include `offer` in `root`.
|
|
608
|
+
* @throws {InvalidTreeHeightError} when the proof height exceeds 20.
|
|
609
|
+
* @example
|
|
610
|
+
* ```ts
|
|
611
|
+
* import { EcrecoverRatifierUtils } from "@morpho-org/midnight-sdk";
|
|
612
|
+
*
|
|
613
|
+
* const verified = await EcrecoverRatifierUtils.verifyRatifierData({
|
|
614
|
+
* chainId: 8453n,
|
|
615
|
+
* offer,
|
|
616
|
+
* ratifierData,
|
|
617
|
+
* });
|
|
618
|
+
* console.log(verified.signer);
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
function verifyRatifierData(params: EcrecoverRatifierDataVerificationParams): Promise<VerifiedEcrecoverRatifierData>;
|
|
504
622
|
/**
|
|
505
623
|
* Signs EcrecoverRatifier typed data through a viem client.
|
|
506
624
|
*
|