@defisaver/positions-sdk 2.1.127-midnight-4-dev → 2.1.127-midnight-5-dev
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/cjs/helpers/morphoMidnightHelpers/index.d.ts +27 -0
- package/cjs/helpers/morphoMidnightHelpers/index.js +41 -5
- package/esm/helpers/morphoMidnightHelpers/index.d.ts +27 -0
- package/esm/helpers/morphoMidnightHelpers/index.js +39 -4
- package/package.json +1 -1
- package/src/helpers/morphoMidnightHelpers/index.ts +72 -4
|
@@ -43,6 +43,17 @@ export interface MorphoMidnightPaybackQuote {
|
|
|
43
43
|
availableUnits: string;
|
|
44
44
|
takeableOffers: any[];
|
|
45
45
|
}
|
|
46
|
+
export interface MorphoMidnightPaybackUnitsQuote {
|
|
47
|
+
bestPrice: string;
|
|
48
|
+
worstPrice: string;
|
|
49
|
+
estPaybackRate: string;
|
|
50
|
+
minRate: string;
|
|
51
|
+
newAssets: string;
|
|
52
|
+
maxAssets: string;
|
|
53
|
+
availableAssets: string;
|
|
54
|
+
availableUnits: string;
|
|
55
|
+
takeableOffers: any[];
|
|
56
|
+
}
|
|
46
57
|
export declare const midnightTimeToMaturityDays: (maturity: number, atSeconds?: number) => number;
|
|
47
58
|
export declare const midnightApyFromPrice: (price: Dec.Value, ttmDays: Dec.Value) => string;
|
|
48
59
|
/**
|
|
@@ -123,3 +134,19 @@ export declare const getMorphoMidnightBorrowQuote: (marketId: string, assetsRaw:
|
|
|
123
134
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
124
135
|
*/
|
|
125
136
|
export declare const getMorphoMidnightPaybackQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackQuote>;
|
|
137
|
+
/**
|
|
138
|
+
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
139
|
+
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
140
|
+
* side, same rate floor, same offer list — but with the two amounts swapped, so the on-chain guard becomes
|
|
141
|
+
* a ceiling on assets spent rather than a floor on units bought.
|
|
142
|
+
*
|
|
143
|
+
* This is what a **full close** must be sized with. Retiring N units costs less than N loan tokens before
|
|
144
|
+
* maturity, so quoting the close as a spend of the debt's face value asks the book for more depth than the
|
|
145
|
+
* close needs (and can be refused for liquidity that is in fact there), and caps the taker's spend at more
|
|
146
|
+
* than the position is worth. Callers that cannot refund an overspend — a taker calling the bundler
|
|
147
|
+
* directly, rather than through an action contract that sweeps the remainder back — need this quote.
|
|
148
|
+
*
|
|
149
|
+
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
150
|
+
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
151
|
+
*/
|
|
152
|
+
export declare const getMorphoMidnightPaybackUnitsQuote: (marketId: string, unitsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackUnitsQuote>;
|
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.getMorphoMidnightPaybackQuote = exports.getMorphoMidnightBorrowQuote = exports.getMorphoMidnightMarketBook = exports.getMorphoMidnightUserBorrowInfo = exports.midnightSlippageParam = exports.midnightPriceFromApy = exports.midnightApyFromPrice = exports.midnightTimeToMaturityDays = exports.getMorphoMidnightAggregatedPositionData = void 0;
|
|
15
|
+
exports.getMorphoMidnightPaybackUnitsQuote = exports.getMorphoMidnightPaybackQuote = exports.getMorphoMidnightBorrowQuote = exports.getMorphoMidnightMarketBook = exports.getMorphoMidnightUserBorrowInfo = exports.midnightSlippageParam = exports.midnightPriceFromApy = exports.midnightApyFromPrice = exports.midnightTimeToMaturityDays = exports.getMorphoMidnightAggregatedPositionData = void 0;
|
|
16
16
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
17
17
|
const tokens_1 = require("@defisaver/tokens");
|
|
18
18
|
const moneymarket_1 = require("../../moneymarket");
|
|
@@ -202,8 +202,9 @@ const midnightQuoteError = (error) => {
|
|
|
202
202
|
return reason ? `Morpho Midnight quote unavailable: ${reason}` : 'Morpho Midnight quote unavailable';
|
|
203
203
|
};
|
|
204
204
|
// The raw quote both sides share: prices descaled from WAD, everything else forwarded verbatim.
|
|
205
|
-
const fetchMorphoMidnightQuote = (marketId, side,
|
|
206
|
-
const
|
|
205
|
+
const fetchMorphoMidnightQuote = (marketId, side, size, slippagePercent) => __awaiter(void 0, void 0, void 0, function* () {
|
|
206
|
+
const [sizeParam, sizeValue] = 'assets' in size ? ['assets', size.assets] : ['units', size.units];
|
|
207
|
+
const url = `${MIDNIGHT_API_BASE}/books/${marketId}/${side}/quote?${sizeParam}=${sizeValue}&slippage=${(0, exports.midnightSlippageParam)(slippagePercent)}`;
|
|
207
208
|
const res = yield fetch(url, { signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT) });
|
|
208
209
|
const json = yield res.json();
|
|
209
210
|
const d = json === null || json === void 0 ? void 0 : json.data;
|
|
@@ -235,7 +236,7 @@ const fetchMorphoMidnightQuote = (marketId, side, assetsRaw, slippagePercent) =>
|
|
|
235
236
|
* Compare the two before submitting and tell the user their ceiling is under the market rate.
|
|
236
237
|
*/
|
|
237
238
|
const getMorphoMidnightBorrowQuote = (marketId, assetsRaw, slippagePercent, maturity, maxBorrowRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
238
|
-
const quote = yield fetchMorphoMidnightQuote(marketId, 'bids', assetsRaw, slippagePercent);
|
|
239
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'bids', { assets: assetsRaw }, slippagePercent);
|
|
239
240
|
const { bestPrice, worstPrice } = quote;
|
|
240
241
|
const ttmDays = (0, exports.midnightTimeToMaturityDays)(maturity);
|
|
241
242
|
const estBorrowRate = (0, exports.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
@@ -272,7 +273,7 @@ exports.getMorphoMidnightBorrowQuote = getMorphoMidnightBorrowQuote;
|
|
|
272
273
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
273
274
|
*/
|
|
274
275
|
const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
275
|
-
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', assetsRaw, slippagePercent);
|
|
276
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { assets: assetsRaw }, slippagePercent);
|
|
276
277
|
const { bestPrice, worstPrice } = quote;
|
|
277
278
|
const ttmDays = (0, exports.midnightTimeToMaturityDays)(maturity);
|
|
278
279
|
const estPaybackRate = (0, exports.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
@@ -290,3 +291,38 @@ const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePercent, mat
|
|
|
290
291
|
minUnits });
|
|
291
292
|
});
|
|
292
293
|
exports.getMorphoMidnightPaybackQuote = getMorphoMidnightPaybackQuote;
|
|
294
|
+
/**
|
|
295
|
+
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
296
|
+
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
297
|
+
* side, same rate floor, same offer list — but with the two amounts swapped, so the on-chain guard becomes
|
|
298
|
+
* a ceiling on assets spent rather than a floor on units bought.
|
|
299
|
+
*
|
|
300
|
+
* This is what a **full close** must be sized with. Retiring N units costs less than N loan tokens before
|
|
301
|
+
* maturity, so quoting the close as a spend of the debt's face value asks the book for more depth than the
|
|
302
|
+
* close needs (and can be refused for liquidity that is in fact there), and caps the taker's spend at more
|
|
303
|
+
* than the position is worth. Callers that cannot refund an overspend — a taker calling the bundler
|
|
304
|
+
* directly, rather than through an action contract that sweeps the remainder back — need this quote.
|
|
305
|
+
*
|
|
306
|
+
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
307
|
+
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
308
|
+
*/
|
|
309
|
+
const getMorphoMidnightPaybackUnitsQuote = (marketId, unitsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
310
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { units: unitsRaw }, slippagePercent);
|
|
311
|
+
const { bestPrice, worstPrice } = quote;
|
|
312
|
+
const ttmDays = (0, exports.midnightTimeToMaturityDays)(maturity);
|
|
313
|
+
const estPaybackRate = (0, exports.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
314
|
+
const capPrice = minPaybackRate !== undefined && new decimal_js_1.default(minPaybackRate).gt(0)
|
|
315
|
+
? (0, exports.midnightPriceFromApy)(minPaybackRate, ttmDays)
|
|
316
|
+
: worstPrice;
|
|
317
|
+
const minRate = (0, exports.midnightApyFromPrice)(capPrice, ttmDays);
|
|
318
|
+
// Rounded UP on both counts — the mirror of the assets-target quote's ROUND_DOWN. Here the figures are
|
|
319
|
+
// what the taker SPENDS, so a value rounded down understates the cost by a base unit and would leave the
|
|
320
|
+
// buy short of the units it was asked for.
|
|
321
|
+
const newAssets = new decimal_js_1.default(unitsRaw).mul(bestPrice).toFixed(0, decimal_js_1.default.ROUND_UP);
|
|
322
|
+
const maxAssets = new decimal_js_1.default(unitsRaw).mul(capPrice).toFixed(0, decimal_js_1.default.ROUND_UP);
|
|
323
|
+
return Object.assign(Object.assign({}, quote), { estPaybackRate,
|
|
324
|
+
minRate,
|
|
325
|
+
newAssets,
|
|
326
|
+
maxAssets });
|
|
327
|
+
});
|
|
328
|
+
exports.getMorphoMidnightPaybackUnitsQuote = getMorphoMidnightPaybackUnitsQuote;
|
|
@@ -43,6 +43,17 @@ export interface MorphoMidnightPaybackQuote {
|
|
|
43
43
|
availableUnits: string;
|
|
44
44
|
takeableOffers: any[];
|
|
45
45
|
}
|
|
46
|
+
export interface MorphoMidnightPaybackUnitsQuote {
|
|
47
|
+
bestPrice: string;
|
|
48
|
+
worstPrice: string;
|
|
49
|
+
estPaybackRate: string;
|
|
50
|
+
minRate: string;
|
|
51
|
+
newAssets: string;
|
|
52
|
+
maxAssets: string;
|
|
53
|
+
availableAssets: string;
|
|
54
|
+
availableUnits: string;
|
|
55
|
+
takeableOffers: any[];
|
|
56
|
+
}
|
|
46
57
|
export declare const midnightTimeToMaturityDays: (maturity: number, atSeconds?: number) => number;
|
|
47
58
|
export declare const midnightApyFromPrice: (price: Dec.Value, ttmDays: Dec.Value) => string;
|
|
48
59
|
/**
|
|
@@ -123,3 +134,19 @@ export declare const getMorphoMidnightBorrowQuote: (marketId: string, assetsRaw:
|
|
|
123
134
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
124
135
|
*/
|
|
125
136
|
export declare const getMorphoMidnightPaybackQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackQuote>;
|
|
137
|
+
/**
|
|
138
|
+
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
139
|
+
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
140
|
+
* side, same rate floor, same offer list — but with the two amounts swapped, so the on-chain guard becomes
|
|
141
|
+
* a ceiling on assets spent rather than a floor on units bought.
|
|
142
|
+
*
|
|
143
|
+
* This is what a **full close** must be sized with. Retiring N units costs less than N loan tokens before
|
|
144
|
+
* maturity, so quoting the close as a spend of the debt's face value asks the book for more depth than the
|
|
145
|
+
* close needs (and can be refused for liquidity that is in fact there), and caps the taker's spend at more
|
|
146
|
+
* than the position is worth. Callers that cannot refund an overspend — a taker calling the bundler
|
|
147
|
+
* directly, rather than through an action contract that sweeps the remainder back — need this quote.
|
|
148
|
+
*
|
|
149
|
+
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
150
|
+
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
151
|
+
*/
|
|
152
|
+
export declare const getMorphoMidnightPaybackUnitsQuote: (marketId: string, unitsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackUnitsQuote>;
|
|
@@ -189,8 +189,9 @@ const midnightQuoteError = (error) => {
|
|
|
189
189
|
return reason ? `Morpho Midnight quote unavailable: ${reason}` : 'Morpho Midnight quote unavailable';
|
|
190
190
|
};
|
|
191
191
|
// The raw quote both sides share: prices descaled from WAD, everything else forwarded verbatim.
|
|
192
|
-
const fetchMorphoMidnightQuote = (marketId, side,
|
|
193
|
-
const
|
|
192
|
+
const fetchMorphoMidnightQuote = (marketId, side, size, slippagePercent) => __awaiter(void 0, void 0, void 0, function* () {
|
|
193
|
+
const [sizeParam, sizeValue] = 'assets' in size ? ['assets', size.assets] : ['units', size.units];
|
|
194
|
+
const url = `${MIDNIGHT_API_BASE}/books/${marketId}/${side}/quote?${sizeParam}=${sizeValue}&slippage=${midnightSlippageParam(slippagePercent)}`;
|
|
194
195
|
const res = yield fetch(url, { signal: AbortSignal.timeout(LONGER_TIMEOUT) });
|
|
195
196
|
const json = yield res.json();
|
|
196
197
|
const d = json === null || json === void 0 ? void 0 : json.data;
|
|
@@ -222,7 +223,7 @@ const fetchMorphoMidnightQuote = (marketId, side, assetsRaw, slippagePercent) =>
|
|
|
222
223
|
* Compare the two before submitting and tell the user their ceiling is under the market rate.
|
|
223
224
|
*/
|
|
224
225
|
export const getMorphoMidnightBorrowQuote = (marketId, assetsRaw, slippagePercent, maturity, maxBorrowRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
|
-
const quote = yield fetchMorphoMidnightQuote(marketId, 'bids', assetsRaw, slippagePercent);
|
|
226
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'bids', { assets: assetsRaw }, slippagePercent);
|
|
226
227
|
const { bestPrice, worstPrice } = quote;
|
|
227
228
|
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
228
229
|
const estBorrowRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
@@ -258,7 +259,7 @@ export const getMorphoMidnightBorrowQuote = (marketId, assetsRaw, slippagePercen
|
|
|
258
259
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
259
260
|
*/
|
|
260
261
|
export const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
-
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', assetsRaw, slippagePercent);
|
|
262
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { assets: assetsRaw }, slippagePercent);
|
|
262
263
|
const { bestPrice, worstPrice } = quote;
|
|
263
264
|
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
264
265
|
const estPaybackRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
@@ -275,3 +276,37 @@ export const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePerce
|
|
|
275
276
|
newUnits,
|
|
276
277
|
minUnits });
|
|
277
278
|
});
|
|
279
|
+
/**
|
|
280
|
+
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
281
|
+
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
282
|
+
* side, same rate floor, same offer list — but with the two amounts swapped, so the on-chain guard becomes
|
|
283
|
+
* a ceiling on assets spent rather than a floor on units bought.
|
|
284
|
+
*
|
|
285
|
+
* This is what a **full close** must be sized with. Retiring N units costs less than N loan tokens before
|
|
286
|
+
* maturity, so quoting the close as a spend of the debt's face value asks the book for more depth than the
|
|
287
|
+
* close needs (and can be refused for liquidity that is in fact there), and caps the taker's spend at more
|
|
288
|
+
* than the position is worth. Callers that cannot refund an overspend — a taker calling the bundler
|
|
289
|
+
* directly, rather than through an action contract that sweeps the remainder back — need this quote.
|
|
290
|
+
*
|
|
291
|
+
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
292
|
+
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
293
|
+
*/
|
|
294
|
+
export const getMorphoMidnightPaybackUnitsQuote = (marketId, unitsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
295
|
+
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { units: unitsRaw }, slippagePercent);
|
|
296
|
+
const { bestPrice, worstPrice } = quote;
|
|
297
|
+
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
298
|
+
const estPaybackRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
299
|
+
const capPrice = minPaybackRate !== undefined && new Dec(minPaybackRate).gt(0)
|
|
300
|
+
? midnightPriceFromApy(minPaybackRate, ttmDays)
|
|
301
|
+
: worstPrice;
|
|
302
|
+
const minRate = midnightApyFromPrice(capPrice, ttmDays);
|
|
303
|
+
// Rounded UP on both counts — the mirror of the assets-target quote's ROUND_DOWN. Here the figures are
|
|
304
|
+
// what the taker SPENDS, so a value rounded down understates the cost by a base unit and would leave the
|
|
305
|
+
// buy short of the units it was asked for.
|
|
306
|
+
const newAssets = new Dec(unitsRaw).mul(bestPrice).toFixed(0, Dec.ROUND_UP);
|
|
307
|
+
const maxAssets = new Dec(unitsRaw).mul(capPrice).toFixed(0, Dec.ROUND_UP);
|
|
308
|
+
return Object.assign(Object.assign({}, quote), { estPaybackRate,
|
|
309
|
+
minRate,
|
|
310
|
+
newAssets,
|
|
311
|
+
maxAssets });
|
|
312
|
+
});
|
package/package.json
CHANGED
|
@@ -173,6 +173,20 @@ export interface MorphoMidnightPaybackQuote {
|
|
|
173
173
|
takeableOffers: any[], // opaque orderbook offers, forwarded verbatim to on-chain execution
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
// Payback quoted the other way round: the caller names the debt units to retire, and the quote prices
|
|
177
|
+
// what buying them costs. Same rate guard as the assets-target quote, expressed as a spend ceiling.
|
|
178
|
+
export interface MorphoMidnightPaybackUnitsQuote {
|
|
179
|
+
bestPrice: string, // average_best_price, loan-per-unit — the cheapest units on the ask side
|
|
180
|
+
worstPrice: string, // average_worst_price, slippage-adjusted (ABOVE best: a dearer unit)
|
|
181
|
+
estPaybackRate: string, // APY the repayment retires debt at, as a percent
|
|
182
|
+
minRate: string, // APY the on-chain ceiling permits, i.e. `maxAssets` annualized (display only)
|
|
183
|
+
newAssets: string, // assets the target units cost at best price, raw loan-token base units
|
|
184
|
+
maxAssets: string, // ceiling on assets spent (on-chain guard), raw loan-token base units
|
|
185
|
+
availableAssets: string,
|
|
186
|
+
availableUnits: string,
|
|
187
|
+
takeableOffers: any[], // opaque orderbook offers, forwarded verbatim to on-chain execution
|
|
188
|
+
}
|
|
189
|
+
|
|
176
190
|
// Days remaining until maturity, optionally measured at a past timestamp (for historical fills).
|
|
177
191
|
export const midnightTimeToMaturityDays = (maturity: number, atSeconds: number = nowInSeconds()): number => new Dec(maturity).sub(atSeconds).div(SECONDS_PER_DAY).toNumber();
|
|
178
192
|
|
|
@@ -302,14 +316,22 @@ interface MidnightParsedQuote {
|
|
|
302
316
|
takeableOffers: any[],
|
|
303
317
|
}
|
|
304
318
|
|
|
319
|
+
/**
|
|
320
|
+
* How much of the book to quote. The endpoint takes exactly one of the two — it rejects a request with
|
|
321
|
+
* neither ("Either assets or units must be provided") — and answers the same `takeable_offers` list either
|
|
322
|
+
* way, since that list is the whole in-band depth rather than the slice this size consumes.
|
|
323
|
+
*/
|
|
324
|
+
type MidnightQuoteSize = { assets: string } | { units: string };
|
|
325
|
+
|
|
305
326
|
// The raw quote both sides share: prices descaled from WAD, everything else forwarded verbatim.
|
|
306
327
|
const fetchMorphoMidnightQuote = async (
|
|
307
328
|
marketId: string,
|
|
308
329
|
side: MorphoMidnightBookSide,
|
|
309
|
-
|
|
330
|
+
size: MidnightQuoteSize,
|
|
310
331
|
slippagePercent: Dec.Value,
|
|
311
332
|
): Promise<MidnightParsedQuote> => {
|
|
312
|
-
const
|
|
333
|
+
const [sizeParam, sizeValue] = 'assets' in size ? ['assets', size.assets] : ['units', size.units];
|
|
334
|
+
const url = `${MIDNIGHT_API_BASE}/books/${marketId}/${side}/quote?${sizeParam}=${sizeValue}&slippage=${midnightSlippageParam(slippagePercent)}`;
|
|
313
335
|
const res = await fetch(url, { signal: AbortSignal.timeout(LONGER_TIMEOUT) });
|
|
314
336
|
const json: { data?: MidnightQuoteResponse, error?: MidnightApiError } = await res.json();
|
|
315
337
|
const d = json?.data;
|
|
@@ -348,7 +370,7 @@ export const getMorphoMidnightBorrowQuote = async (
|
|
|
348
370
|
maturity: number,
|
|
349
371
|
maxBorrowRate?: Dec.Value,
|
|
350
372
|
): Promise<MorphoMidnightBorrowQuote> => {
|
|
351
|
-
const quote = await fetchMorphoMidnightQuote(marketId, 'bids', assetsRaw, slippagePercent);
|
|
373
|
+
const quote = await fetchMorphoMidnightQuote(marketId, 'bids', { assets: assetsRaw }, slippagePercent);
|
|
352
374
|
const { bestPrice, worstPrice } = quote;
|
|
353
375
|
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
354
376
|
const estBorrowRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
@@ -396,7 +418,7 @@ export const getMorphoMidnightPaybackQuote = async (
|
|
|
396
418
|
maturity: number,
|
|
397
419
|
minPaybackRate?: Dec.Value,
|
|
398
420
|
): Promise<MorphoMidnightPaybackQuote> => {
|
|
399
|
-
const quote = await fetchMorphoMidnightQuote(marketId, 'asks', assetsRaw, slippagePercent);
|
|
421
|
+
const quote = await fetchMorphoMidnightQuote(marketId, 'asks', { assets: assetsRaw }, slippagePercent);
|
|
400
422
|
const { bestPrice, worstPrice } = quote;
|
|
401
423
|
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
402
424
|
const estPaybackRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
@@ -418,3 +440,49 @@ export const getMorphoMidnightPaybackQuote = async (
|
|
|
418
440
|
minUnits,
|
|
419
441
|
};
|
|
420
442
|
};
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
446
|
+
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
447
|
+
* side, same rate floor, same offer list — but with the two amounts swapped, so the on-chain guard becomes
|
|
448
|
+
* a ceiling on assets spent rather than a floor on units bought.
|
|
449
|
+
*
|
|
450
|
+
* This is what a **full close** must be sized with. Retiring N units costs less than N loan tokens before
|
|
451
|
+
* maturity, so quoting the close as a spend of the debt's face value asks the book for more depth than the
|
|
452
|
+
* close needs (and can be refused for liquidity that is in fact there), and caps the taker's spend at more
|
|
453
|
+
* than the position is worth. Callers that cannot refund an overspend — a taker calling the bundler
|
|
454
|
+
* directly, rather than through an action contract that sweeps the remainder back — need this quote.
|
|
455
|
+
*
|
|
456
|
+
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
457
|
+
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
458
|
+
*/
|
|
459
|
+
export const getMorphoMidnightPaybackUnitsQuote = async (
|
|
460
|
+
marketId: string,
|
|
461
|
+
unitsRaw: string,
|
|
462
|
+
slippagePercent: Dec.Value,
|
|
463
|
+
maturity: number,
|
|
464
|
+
minPaybackRate?: Dec.Value,
|
|
465
|
+
): Promise<MorphoMidnightPaybackUnitsQuote> => {
|
|
466
|
+
const quote = await fetchMorphoMidnightQuote(marketId, 'asks', { units: unitsRaw }, slippagePercent);
|
|
467
|
+
const { bestPrice, worstPrice } = quote;
|
|
468
|
+
const ttmDays = midnightTimeToMaturityDays(maturity);
|
|
469
|
+
const estPaybackRate = midnightApyFromPrice(bestPrice, ttmDays);
|
|
470
|
+
|
|
471
|
+
const capPrice = minPaybackRate !== undefined && new Dec(minPaybackRate).gt(0)
|
|
472
|
+
? midnightPriceFromApy(minPaybackRate, ttmDays)
|
|
473
|
+
: worstPrice;
|
|
474
|
+
const minRate = midnightApyFromPrice(capPrice, ttmDays);
|
|
475
|
+
// Rounded UP on both counts — the mirror of the assets-target quote's ROUND_DOWN. Here the figures are
|
|
476
|
+
// what the taker SPENDS, so a value rounded down understates the cost by a base unit and would leave the
|
|
477
|
+
// buy short of the units it was asked for.
|
|
478
|
+
const newAssets = new Dec(unitsRaw).mul(bestPrice).toFixed(0, Dec.ROUND_UP);
|
|
479
|
+
const maxAssets = new Dec(unitsRaw).mul(capPrice).toFixed(0, Dec.ROUND_UP);
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
...quote,
|
|
483
|
+
estPaybackRate,
|
|
484
|
+
minRate,
|
|
485
|
+
newAssets,
|
|
486
|
+
maxAssets,
|
|
487
|
+
};
|
|
488
|
+
};
|