@defisaver/positions-sdk 2.1.127-midnight-5-dev → 2.1.127-midnight-7-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/constants/index.d.ts +1 -0
- package/cjs/constants/index.js +2 -1
- package/cjs/helpers/morphoMidnightHelpers/index.d.ts +8 -14
- package/cjs/helpers/morphoMidnightHelpers/index.js +50 -62
- package/cjs/helpers/morphoMidnightHelpers/rate.d.ts +11 -0
- package/cjs/helpers/morphoMidnightHelpers/rate.js +49 -0
- package/cjs/helpers/morphoMidnightHelpers/tenor.d.ts +125 -0
- package/cjs/helpers/morphoMidnightHelpers/tenor.js +256 -0
- package/cjs/markets/index.d.ts +1 -1
- package/cjs/markets/index.js +3 -1
- package/cjs/markets/morphoMidnight/index.d.ts +45 -1
- package/cjs/markets/morphoMidnight/index.js +542 -42
- package/cjs/types/morphoMidnight.d.ts +22 -1
- package/cjs/types/morphoMidnight.js +16 -0
- package/esm/constants/index.d.ts +1 -0
- package/esm/constants/index.js +1 -0
- package/esm/helpers/morphoMidnightHelpers/index.d.ts +8 -14
- package/esm/helpers/morphoMidnightHelpers/index.js +27 -45
- package/esm/helpers/morphoMidnightHelpers/rate.d.ts +11 -0
- package/esm/helpers/morphoMidnightHelpers/rate.js +38 -0
- package/esm/helpers/morphoMidnightHelpers/tenor.d.ts +125 -0
- package/esm/helpers/morphoMidnightHelpers/tenor.js +239 -0
- package/esm/markets/index.d.ts +1 -1
- package/esm/markets/index.js +1 -1
- package/esm/markets/morphoMidnight/index.d.ts +45 -1
- package/esm/markets/morphoMidnight/index.js +507 -24
- package/esm/types/morphoMidnight.d.ts +22 -1
- package/esm/types/morphoMidnight.js +16 -0
- package/package.json +1 -1
- package/src/constants/index.ts +1 -0
- package/src/helpers/morphoMidnightHelpers/index.ts +49 -45
- package/src/helpers/morphoMidnightHelpers/rate.ts +46 -0
- package/src/helpers/morphoMidnightHelpers/tenor.ts +411 -0
- package/src/markets/index.ts +3 -1
- package/src/markets/morphoMidnight/index.ts +538 -24
- package/src/types/morphoMidnight.ts +23 -0
package/cjs/constants/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare const SECONDS_PER_WEEK: number;
|
|
|
6
6
|
export declare const AVG_BLOCK_TIME = 12;
|
|
7
7
|
export declare const BLOCKS_IN_A_YEAR: number;
|
|
8
8
|
export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
export declare const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
9
10
|
export declare const WAD = 1000000000000000000;
|
|
10
11
|
export declare const USD_QUOTE = "0x0000000000000000000000000000000000000348";
|
|
11
12
|
export declare const borrowOperations: string[];
|
package/cjs/constants/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.borrowOperations = exports.USD_QUOTE = exports.WAD = exports.ZERO_ADDRESS = exports.BLOCKS_IN_A_YEAR = exports.AVG_BLOCK_TIME = exports.SECONDS_PER_WEEK = exports.SECONDS_PER_YEAR = exports.SECONDS_PER_DAY = exports.SECONDS_PER_HOUR = exports.SECONDS_PER_MINUTE = void 0;
|
|
3
|
+
exports.borrowOperations = exports.USD_QUOTE = exports.WAD = exports.ZERO_BYTES32 = exports.ZERO_ADDRESS = exports.BLOCKS_IN_A_YEAR = exports.AVG_BLOCK_TIME = exports.SECONDS_PER_WEEK = exports.SECONDS_PER_YEAR = exports.SECONDS_PER_DAY = exports.SECONDS_PER_HOUR = exports.SECONDS_PER_MINUTE = void 0;
|
|
4
4
|
exports.SECONDS_PER_MINUTE = 60;
|
|
5
5
|
exports.SECONDS_PER_HOUR = 60 * exports.SECONDS_PER_MINUTE;
|
|
6
6
|
exports.SECONDS_PER_DAY = 24 * exports.SECONDS_PER_HOUR;
|
|
@@ -9,6 +9,7 @@ exports.SECONDS_PER_WEEK = 7 * exports.SECONDS_PER_DAY;
|
|
|
9
9
|
exports.AVG_BLOCK_TIME = 12;
|
|
10
10
|
exports.BLOCKS_IN_A_YEAR = exports.SECONDS_PER_YEAR / exports.AVG_BLOCK_TIME;
|
|
11
11
|
exports.ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
12
|
+
exports.ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
12
13
|
exports.WAD = 1e18;
|
|
13
14
|
exports.USD_QUOTE = '0x0000000000000000000000000000000000000348';
|
|
14
15
|
exports.borrowOperations = ['borrow', 'payback'];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
2
|
import { MMUsedAssets, NetworkNumber } from '../../types/common';
|
|
3
3
|
import { MorphoMidnightAggregatedPositionData, MorphoMidnightAssetsData, MorphoMidnightBookSide, MorphoMidnightMarketData, MorphoMidnightMarketInfo, MorphoMidnightParsedBook } from '../../types';
|
|
4
|
+
export { buildMidnightParsedBook, midnightApyFromPrice, midnightBookBestFirst, midnightPriceFromApy, midnightTimeToMaturityDays, } from './rate';
|
|
5
|
+
export { tenorBookKeyFor, tenorBookRateToApyPercent, tenorOfferFillToApiFill, tenorOfferToApiOffer, } from './tenor';
|
|
4
6
|
/**
|
|
5
7
|
* Aggregate a Morpho Midnight position. Midnight markets are multi-collateral, so the borrow limit is
|
|
6
8
|
* the sum of each collateral's USD value times its own lltv (Aave-v4 style), rather than a single pair.
|
|
@@ -54,17 +56,6 @@ export interface MorphoMidnightPaybackUnitsQuote {
|
|
|
54
56
|
availableUnits: string;
|
|
55
57
|
takeableOffers: any[];
|
|
56
58
|
}
|
|
57
|
-
export declare const midnightTimeToMaturityDays: (maturity: number, atSeconds?: number) => number;
|
|
58
|
-
export declare const midnightApyFromPrice: (price: Dec.Value, ttmDays: Dec.Value) => string;
|
|
59
|
-
/**
|
|
60
|
-
* Inverse of `midnightApyFromPrice`: the loan-per-unit price a borrow APY implies,
|
|
61
|
-
* price = (1 + rate)^(−ttmDays / 365).
|
|
62
|
-
*
|
|
63
|
-
* This is what turns an absolute rate ceiling into an on-chain `maxUnits` cap (units = assets / price),
|
|
64
|
-
* and equally the principal a unit of borrow power is worth — Midnight debt is recorded at its maturity
|
|
65
|
-
* face value, so borrowing the full limit as principal would overshoot it by the interest.
|
|
66
|
-
*/
|
|
67
|
-
export declare const midnightPriceFromApy: (ratePercent: Dec.Value, ttmDays: Dec.Value) => string;
|
|
68
59
|
/**
|
|
69
60
|
* Coerce a slippage into what the quote endpoint accepts: 0.1–100 with at most one decimal place. The
|
|
70
61
|
* validation is lexical, so a computed value (`4.15066671050631467`) is rejected outright — without this
|
|
@@ -113,8 +104,11 @@ export declare const getMorphoMidnightMarketBook: (market: MorphoMidnightMarketD
|
|
|
113
104
|
*
|
|
114
105
|
* A `maxBorrowRate` below `estBorrowRate` yields `maxUnits < newUnits` — the borrow would revert on-chain.
|
|
115
106
|
* Compare the two before submitting and tell the user their ceiling is under the market rate.
|
|
107
|
+
*
|
|
108
|
+
* Tenor-hosted markets (see `isTenorMidnightMarket`) are quoted against Tenor's router instead of Morpho's
|
|
109
|
+
* book API. Slippage is applied locally to `maxUnits`; `taker` is the position owner (the smart wallet).
|
|
116
110
|
*/
|
|
117
|
-
export declare const getMorphoMidnightBorrowQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, maxBorrowRate?: Dec.Value) => Promise<MorphoMidnightBorrowQuote>;
|
|
111
|
+
export declare const getMorphoMidnightBorrowQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, maxBorrowRate?: Dec.Value, taker?: string) => Promise<MorphoMidnightBorrowQuote>;
|
|
118
112
|
/**
|
|
119
113
|
* Quote a prospective payback against the ask side of the Midnight order book: the rate the repayment
|
|
120
114
|
* retires debt at, the debt units it buys, and the `minUnits` floor sent on-chain to protect the user if
|
|
@@ -133,7 +127,7 @@ export declare const getMorphoMidnightBorrowQuote: (marketId: string, assetsRaw:
|
|
|
133
127
|
* A `minPaybackRate` above `estPaybackRate` yields `minUnits > newUnits` — the payback would revert
|
|
134
128
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
135
129
|
*/
|
|
136
|
-
export declare const getMorphoMidnightPaybackQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackQuote>;
|
|
130
|
+
export declare const getMorphoMidnightPaybackQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value, taker?: string) => Promise<MorphoMidnightPaybackQuote>;
|
|
137
131
|
/**
|
|
138
132
|
* Payback quoted against a **units** target instead of a spend: "retire exactly these debt units, and tell
|
|
139
133
|
* me what that costs". The sibling of `getMorphoMidnightPaybackQuote` in every other respect — same ask
|
|
@@ -149,4 +143,4 @@ export declare const getMorphoMidnightPaybackQuote: (marketId: string, assetsRaw
|
|
|
149
143
|
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
150
144
|
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
151
145
|
*/
|
|
152
|
-
export declare const getMorphoMidnightPaybackUnitsQuote: (marketId: string, unitsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value) => Promise<MorphoMidnightPaybackUnitsQuote>;
|
|
146
|
+
export declare const getMorphoMidnightPaybackUnitsQuote: (marketId: string, unitsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value, taker?: string) => 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.getMorphoMidnightPaybackUnitsQuote = exports.getMorphoMidnightPaybackQuote = exports.getMorphoMidnightBorrowQuote = exports.getMorphoMidnightMarketBook = exports.getMorphoMidnightUserBorrowInfo = exports.midnightSlippageParam = exports.
|
|
15
|
+
exports.getMorphoMidnightPaybackUnitsQuote = exports.getMorphoMidnightPaybackQuote = exports.getMorphoMidnightBorrowQuote = exports.getMorphoMidnightMarketBook = exports.getMorphoMidnightUserBorrowInfo = exports.midnightSlippageParam = exports.getMorphoMidnightAggregatedPositionData = exports.tenorOfferToApiOffer = exports.tenorOfferFillToApiFill = exports.tenorBookRateToApyPercent = exports.tenorBookKeyFor = exports.midnightTimeToMaturityDays = exports.midnightPriceFromApy = exports.midnightBookBestFirst = exports.midnightApyFromPrice = exports.buildMidnightParsedBook = 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");
|
|
@@ -20,6 +20,20 @@ const staking_1 = require("../../staking");
|
|
|
20
20
|
const common_1 = require("../../types/common");
|
|
21
21
|
const constants_1 = require("../../constants");
|
|
22
22
|
const utils_1 = require("../../services/utils");
|
|
23
|
+
const morphoMidnight_1 = require("../../markets/morphoMidnight");
|
|
24
|
+
const rate_1 = require("./rate");
|
|
25
|
+
const tenor_1 = require("./tenor");
|
|
26
|
+
var rate_2 = require("./rate");
|
|
27
|
+
Object.defineProperty(exports, "buildMidnightParsedBook", { enumerable: true, get: function () { return rate_2.buildMidnightParsedBook; } });
|
|
28
|
+
Object.defineProperty(exports, "midnightApyFromPrice", { enumerable: true, get: function () { return rate_2.midnightApyFromPrice; } });
|
|
29
|
+
Object.defineProperty(exports, "midnightBookBestFirst", { enumerable: true, get: function () { return rate_2.midnightBookBestFirst; } });
|
|
30
|
+
Object.defineProperty(exports, "midnightPriceFromApy", { enumerable: true, get: function () { return rate_2.midnightPriceFromApy; } });
|
|
31
|
+
Object.defineProperty(exports, "midnightTimeToMaturityDays", { enumerable: true, get: function () { return rate_2.midnightTimeToMaturityDays; } });
|
|
32
|
+
var tenor_2 = require("./tenor");
|
|
33
|
+
Object.defineProperty(exports, "tenorBookKeyFor", { enumerable: true, get: function () { return tenor_2.tenorBookKeyFor; } });
|
|
34
|
+
Object.defineProperty(exports, "tenorBookRateToApyPercent", { enumerable: true, get: function () { return tenor_2.tenorBookRateToApyPercent; } });
|
|
35
|
+
Object.defineProperty(exports, "tenorOfferFillToApiFill", { enumerable: true, get: function () { return tenor_2.tenorOfferFillToApiFill; } });
|
|
36
|
+
Object.defineProperty(exports, "tenorOfferToApiOffer", { enumerable: true, get: function () { return tenor_2.tenorOfferToApiOffer; } });
|
|
23
37
|
/**
|
|
24
38
|
* Aggregate a Morpho Midnight position. Midnight markets are multi-collateral, so the borrow limit is
|
|
25
39
|
* the sum of each collateral's USD value times its own lltv (Aave-v4 style), rather than a single pair.
|
|
@@ -85,7 +99,6 @@ exports.getMorphoMidnightAggregatedPositionData = getMorphoMidnightAggregatedPos
|
|
|
85
99
|
// Quote prices are WAD-scaled
|
|
86
100
|
// loan-per-unit ratios (< 1 for a discounted fixed-term borrow); annualizing them yields the borrow APY.
|
|
87
101
|
const MIDNIGHT_API_BASE = 'https://api.morpho.org/v0/midnight';
|
|
88
|
-
const nowInSeconds = () => Math.floor(Date.now() / 1000);
|
|
89
102
|
// The book endpoint is markedly slower than the rest of the API — `LONGER_TIMEOUT` (5s) aborts it often
|
|
90
103
|
// enough that markets drop out of the list for no reason.
|
|
91
104
|
const MIDNIGHT_BOOK_TIMEOUT = 30000;
|
|
@@ -93,37 +106,6 @@ const MIDNIGHT_BOOK_TIMEOUT = 30000;
|
|
|
93
106
|
// place (`0.50` is rejected even though `0.5` passes). See `midnightSlippageParam`.
|
|
94
107
|
const MIDNIGHT_SLIPPAGE_MIN = 0.1;
|
|
95
108
|
const MIDNIGHT_SLIPPAGE_MAX = 100;
|
|
96
|
-
// Days remaining until maturity, optionally measured at a past timestamp (for historical fills).
|
|
97
|
-
const midnightTimeToMaturityDays = (maturity, atSeconds = nowInSeconds()) => new decimal_js_1.default(maturity).sub(atSeconds).div(constants_1.SECONDS_PER_DAY).toNumber();
|
|
98
|
-
exports.midnightTimeToMaturityDays = midnightTimeToMaturityDays;
|
|
99
|
-
// Annualize a fixed-term discount price into an APY percent: (1 / price)^(365 / ttmDays) − 1.
|
|
100
|
-
// `price` is loan-per-unit (assets received / units owed), so 1/price ≥ 1.
|
|
101
|
-
const midnightApyFromPrice = (price, ttmDays) => {
|
|
102
|
-
const p = new decimal_js_1.default(price);
|
|
103
|
-
const ttm = new decimal_js_1.default(ttmDays);
|
|
104
|
-
if (p.lte(0) || ttm.lte(0))
|
|
105
|
-
return '0';
|
|
106
|
-
return new decimal_js_1.default(1).div(p).pow(new decimal_js_1.default(365).div(ttm)).sub(1)
|
|
107
|
-
.mul(100)
|
|
108
|
-
.toString();
|
|
109
|
-
};
|
|
110
|
-
exports.midnightApyFromPrice = midnightApyFromPrice;
|
|
111
|
-
/**
|
|
112
|
-
* Inverse of `midnightApyFromPrice`: the loan-per-unit price a borrow APY implies,
|
|
113
|
-
* price = (1 + rate)^(−ttmDays / 365).
|
|
114
|
-
*
|
|
115
|
-
* This is what turns an absolute rate ceiling into an on-chain `maxUnits` cap (units = assets / price),
|
|
116
|
-
* and equally the principal a unit of borrow power is worth — Midnight debt is recorded at its maturity
|
|
117
|
-
* face value, so borrowing the full limit as principal would overshoot it by the interest.
|
|
118
|
-
*/
|
|
119
|
-
const midnightPriceFromApy = (ratePercent, ttmDays) => {
|
|
120
|
-
const rate = new decimal_js_1.default(ratePercent);
|
|
121
|
-
const ttm = new decimal_js_1.default(ttmDays);
|
|
122
|
-
if (rate.lte(0) || ttm.lte(0))
|
|
123
|
-
return '1';
|
|
124
|
-
return new decimal_js_1.default(1).div(new decimal_js_1.default(1).add(rate.div(100)).pow(ttm.div(365))).toString();
|
|
125
|
-
};
|
|
126
|
-
exports.midnightPriceFromApy = midnightPriceFromApy;
|
|
127
109
|
/**
|
|
128
110
|
* Coerce a slippage into what the quote endpoint accepts: 0.1–100 with at most one decimal place. The
|
|
129
111
|
* validation is lexical, so a computed value (`4.15066671050631467`) is rejected outright — without this
|
|
@@ -171,26 +153,20 @@ exports.getMorphoMidnightUserBorrowInfo = getMorphoMidnightUserBorrowInfo;
|
|
|
171
153
|
*/
|
|
172
154
|
const getMorphoMidnightMarketBook = (market_1, network_1, ...args_1) => __awaiter(void 0, [market_1, network_1, ...args_1], void 0, function* (market, network, side = 'bids') {
|
|
173
155
|
var _a;
|
|
156
|
+
if ((0, morphoMidnight_1.isTenorMidnightMarket)(market)) {
|
|
157
|
+
return (0, tenor_1.getTenorMarketBook)(market, network, side);
|
|
158
|
+
}
|
|
174
159
|
const loanSymbol = (0, tokens_1.getAssetInfoByAddress)(market.loanToken, network).symbol;
|
|
175
160
|
const res = yield fetch(`${MIDNIGHT_API_BASE}/books/${market.marketId}`, { signal: AbortSignal.timeout(MIDNIGHT_BOOK_TIMEOUT) });
|
|
176
161
|
if (!res.ok)
|
|
177
162
|
throw new Error(`Midnight book request failed for ${market.value} (${res.status})`);
|
|
178
163
|
const json = yield res.json();
|
|
179
|
-
const ttmDays = (0,
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
.map((offer) => ({
|
|
183
|
-
rate: (0, exports.midnightApyFromPrice)(new decimal_js_1.default(offer.price).div(constants_1.WAD), ttmDays),
|
|
164
|
+
const ttmDays = (0, rate_1.midnightTimeToMaturityDays)(market.maturity);
|
|
165
|
+
const offers = (((_a = json === null || json === void 0 ? void 0 : json.data) === null || _a === void 0 ? void 0 : _a[side]) || []).map((offer) => ({
|
|
166
|
+
rate: (0, rate_1.midnightApyFromPrice)(new decimal_js_1.default(offer.price).div(constants_1.WAD), ttmDays),
|
|
184
167
|
liquidity: (0, tokens_1.assetAmountInEth)(offer.assets, loanSymbol),
|
|
185
|
-
}))
|
|
186
|
-
|
|
187
|
-
if (offers.length === 0)
|
|
188
|
-
return null;
|
|
189
|
-
return {
|
|
190
|
-
bestRate: offers[0].rate,
|
|
191
|
-
totalLiquidity: offers.reduce((sum, offer) => sum.add(offer.liquidity), new decimal_js_1.default(0)).toString(),
|
|
192
|
-
offers,
|
|
193
|
-
};
|
|
168
|
+
}));
|
|
169
|
+
return (0, rate_1.buildMidnightParsedBook)(offers, side);
|
|
194
170
|
});
|
|
195
171
|
exports.getMorphoMidnightMarketBook = getMorphoMidnightMarketBook;
|
|
196
172
|
// The API says why a quote failed — NOT_FOUND (market matured or not open yet), INSUFFICIENT_LIQUIDITY
|
|
@@ -234,18 +210,24 @@ const fetchMorphoMidnightQuote = (marketId, side, size, slippagePercent) => __aw
|
|
|
234
210
|
*
|
|
235
211
|
* A `maxBorrowRate` below `estBorrowRate` yields `maxUnits < newUnits` — the borrow would revert on-chain.
|
|
236
212
|
* Compare the two before submitting and tell the user their ceiling is under the market rate.
|
|
213
|
+
*
|
|
214
|
+
* Tenor-hosted markets (see `isTenorMidnightMarket`) are quoted against Tenor's router instead of Morpho's
|
|
215
|
+
* book API. Slippage is applied locally to `maxUnits`; `taker` is the position owner (the smart wallet).
|
|
237
216
|
*/
|
|
238
|
-
const getMorphoMidnightBorrowQuote = (marketId, assetsRaw, slippagePercent, maturity, maxBorrowRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
217
|
+
const getMorphoMidnightBorrowQuote = (marketId, assetsRaw, slippagePercent, maturity, maxBorrowRate, taker) => __awaiter(void 0, void 0, void 0, function* () {
|
|
218
|
+
if ((0, morphoMidnight_1.isTenorMidnightMarket)(marketId)) {
|
|
219
|
+
return (0, tenor_1.getTenorBorrowQuote)(marketId, assetsRaw, slippagePercent, maturity, maxBorrowRate, taker);
|
|
220
|
+
}
|
|
239
221
|
const quote = yield fetchMorphoMidnightQuote(marketId, 'bids', { assets: assetsRaw }, slippagePercent);
|
|
240
222
|
const { bestPrice, worstPrice } = quote;
|
|
241
|
-
const ttmDays = (0,
|
|
242
|
-
const estBorrowRate = (0,
|
|
223
|
+
const ttmDays = (0, rate_1.midnightTimeToMaturityDays)(maturity);
|
|
224
|
+
const estBorrowRate = (0, rate_1.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
243
225
|
// Price the cap sits at, and the rate that price represents — one derivation, so `maxRate` and
|
|
244
226
|
// `maxUnits` can never disagree about what the user is protected at.
|
|
245
227
|
const capPrice = maxBorrowRate !== undefined && new decimal_js_1.default(maxBorrowRate).gt(0)
|
|
246
|
-
? (0,
|
|
228
|
+
? (0, rate_1.midnightPriceFromApy)(maxBorrowRate, ttmDays)
|
|
247
229
|
: worstPrice;
|
|
248
|
-
const maxRate = (0,
|
|
230
|
+
const maxRate = (0, rate_1.midnightApyFromPrice)(capPrice, ttmDays);
|
|
249
231
|
const newUnits = new decimal_js_1.default(bestPrice).lte(0) ? '0' : new decimal_js_1.default(assetsRaw).div(bestPrice).toFixed(0);
|
|
250
232
|
const maxUnits = new decimal_js_1.default(capPrice).lte(0) ? '0' : new decimal_js_1.default(assetsRaw).div(capPrice).toFixed(0);
|
|
251
233
|
return Object.assign(Object.assign({}, quote), { estBorrowRate,
|
|
@@ -272,15 +254,18 @@ exports.getMorphoMidnightBorrowQuote = getMorphoMidnightBorrowQuote;
|
|
|
272
254
|
* A `minPaybackRate` above `estPaybackRate` yields `minUnits > newUnits` — the payback would revert
|
|
273
255
|
* on-chain. Compare the two before submitting and tell the user their floor is over the market rate.
|
|
274
256
|
*/
|
|
275
|
-
const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
257
|
+
const getMorphoMidnightPaybackQuote = (marketId, assetsRaw, slippagePercent, maturity, minPaybackRate, taker) => __awaiter(void 0, void 0, void 0, function* () {
|
|
258
|
+
if ((0, morphoMidnight_1.isTenorMidnightMarket)(marketId)) {
|
|
259
|
+
return (0, tenor_1.getTenorPaybackQuote)(marketId, assetsRaw, slippagePercent, maturity, minPaybackRate, taker);
|
|
260
|
+
}
|
|
276
261
|
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { assets: assetsRaw }, slippagePercent);
|
|
277
262
|
const { bestPrice, worstPrice } = quote;
|
|
278
|
-
const ttmDays = (0,
|
|
279
|
-
const estPaybackRate = (0,
|
|
263
|
+
const ttmDays = (0, rate_1.midnightTimeToMaturityDays)(maturity);
|
|
264
|
+
const estPaybackRate = (0, rate_1.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
280
265
|
const capPrice = minPaybackRate !== undefined && new decimal_js_1.default(minPaybackRate).gt(0)
|
|
281
|
-
? (0,
|
|
266
|
+
? (0, rate_1.midnightPriceFromApy)(minPaybackRate, ttmDays)
|
|
282
267
|
: worstPrice;
|
|
283
|
-
const minRate = (0,
|
|
268
|
+
const minRate = (0, rate_1.midnightApyFromPrice)(capPrice, ttmDays);
|
|
284
269
|
// Rounded down on both counts: `newUnits` must not overstate the debt the user sees retired, and a
|
|
285
270
|
// `minUnits` rounded up would be a stricter floor than asked for and revert a payback that was fine.
|
|
286
271
|
const newUnits = new decimal_js_1.default(bestPrice).lte(0) ? '0' : new decimal_js_1.default(assetsRaw).div(bestPrice).toFixed(0, decimal_js_1.default.ROUND_DOWN);
|
|
@@ -306,15 +291,18 @@ exports.getMorphoMidnightPaybackQuote = getMorphoMidnightPaybackQuote;
|
|
|
306
291
|
* A `minPaybackRate` above `estPaybackRate` yields `maxAssets < newAssets`: the ceiling is under what the
|
|
307
292
|
* buy costs and it would revert on-chain, the mirror of the assets-target quote's `minUnits > newUnits`.
|
|
308
293
|
*/
|
|
309
|
-
const getMorphoMidnightPaybackUnitsQuote = (marketId, unitsRaw, slippagePercent, maturity, minPaybackRate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
294
|
+
const getMorphoMidnightPaybackUnitsQuote = (marketId, unitsRaw, slippagePercent, maturity, minPaybackRate, taker) => __awaiter(void 0, void 0, void 0, function* () {
|
|
295
|
+
if ((0, morphoMidnight_1.isTenorMidnightMarket)(marketId)) {
|
|
296
|
+
return (0, tenor_1.getTenorPaybackUnitsQuote)(marketId, unitsRaw, slippagePercent, maturity, minPaybackRate, taker);
|
|
297
|
+
}
|
|
310
298
|
const quote = yield fetchMorphoMidnightQuote(marketId, 'asks', { units: unitsRaw }, slippagePercent);
|
|
311
299
|
const { bestPrice, worstPrice } = quote;
|
|
312
|
-
const ttmDays = (0,
|
|
313
|
-
const estPaybackRate = (0,
|
|
300
|
+
const ttmDays = (0, rate_1.midnightTimeToMaturityDays)(maturity);
|
|
301
|
+
const estPaybackRate = (0, rate_1.midnightApyFromPrice)(bestPrice, ttmDays);
|
|
314
302
|
const capPrice = minPaybackRate !== undefined && new decimal_js_1.default(minPaybackRate).gt(0)
|
|
315
|
-
? (0,
|
|
303
|
+
? (0, rate_1.midnightPriceFromApy)(minPaybackRate, ttmDays)
|
|
316
304
|
: worstPrice;
|
|
317
|
-
const minRate = (0,
|
|
305
|
+
const minRate = (0, rate_1.midnightApyFromPrice)(capPrice, ttmDays);
|
|
318
306
|
// Rounded UP on both counts — the mirror of the assets-target quote's ROUND_DOWN. Here the figures are
|
|
319
307
|
// what the taker SPENDS, so a value rounded down understates the cost by a base unit and would leave the
|
|
320
308
|
// buy short of the units it was asked for.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Dec from 'decimal.js';
|
|
2
|
+
import { MorphoMidnightBookOffer, MorphoMidnightBookSide, MorphoMidnightParsedBook } from '../../types';
|
|
3
|
+
export declare const midnightTimeToMaturityDays: (maturity: number, atSeconds?: number) => number;
|
|
4
|
+
export declare const midnightApyFromPrice: (price: Dec.Value, ttmDays: Dec.Value) => string;
|
|
5
|
+
/**
|
|
6
|
+
* Inverse of `midnightApyFromPrice`: the loan-per-unit price a borrow APY implies,
|
|
7
|
+
* price = (1 + rate)^(−ttmDays / 365).
|
|
8
|
+
*/
|
|
9
|
+
export declare const midnightPriceFromApy: (ratePercent: Dec.Value, ttmDays: Dec.Value) => string;
|
|
10
|
+
export declare const midnightBookBestFirst: (side: MorphoMidnightBookSide) => 1 | -1;
|
|
11
|
+
export declare const buildMidnightParsedBook: (offers: MorphoMidnightBookOffer[], side: MorphoMidnightBookSide) => MorphoMidnightParsedBook | null;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildMidnightParsedBook = exports.midnightBookBestFirst = exports.midnightPriceFromApy = exports.midnightApyFromPrice = exports.midnightTimeToMaturityDays = void 0;
|
|
7
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
8
|
+
const constants_1 = require("../../constants");
|
|
9
|
+
const nowInSeconds = () => Math.floor(Date.now() / 1000);
|
|
10
|
+
// Days remaining until maturity, optionally measured at a past timestamp (for historical fills).
|
|
11
|
+
const midnightTimeToMaturityDays = (maturity, atSeconds = nowInSeconds()) => new decimal_js_1.default(maturity).sub(atSeconds).div(constants_1.SECONDS_PER_DAY).toNumber();
|
|
12
|
+
exports.midnightTimeToMaturityDays = midnightTimeToMaturityDays;
|
|
13
|
+
// Annualize a fixed-term discount price into an APY percent: (1 / price)^(365 / ttmDays) − 1.
|
|
14
|
+
// `price` is loan-per-unit (assets received / units owed), so 1/price ≥ 1.
|
|
15
|
+
const midnightApyFromPrice = (price, ttmDays) => {
|
|
16
|
+
const p = new decimal_js_1.default(price);
|
|
17
|
+
const ttm = new decimal_js_1.default(ttmDays);
|
|
18
|
+
if (p.lte(0) || ttm.lte(0))
|
|
19
|
+
return '0';
|
|
20
|
+
return new decimal_js_1.default(1).div(p).pow(new decimal_js_1.default(365).div(ttm)).sub(1)
|
|
21
|
+
.mul(100)
|
|
22
|
+
.toString();
|
|
23
|
+
};
|
|
24
|
+
exports.midnightApyFromPrice = midnightApyFromPrice;
|
|
25
|
+
/**
|
|
26
|
+
* Inverse of `midnightApyFromPrice`: the loan-per-unit price a borrow APY implies,
|
|
27
|
+
* price = (1 + rate)^(−ttmDays / 365).
|
|
28
|
+
*/
|
|
29
|
+
const midnightPriceFromApy = (ratePercent, ttmDays) => {
|
|
30
|
+
const rate = new decimal_js_1.default(ratePercent);
|
|
31
|
+
const ttm = new decimal_js_1.default(ttmDays);
|
|
32
|
+
if (rate.lte(0) || ttm.lte(0))
|
|
33
|
+
return '1';
|
|
34
|
+
return new decimal_js_1.default(1).div(new decimal_js_1.default(1).add(rate.div(100)).pow(ttm.div(365))).toString();
|
|
35
|
+
};
|
|
36
|
+
exports.midnightPriceFromApy = midnightPriceFromApy;
|
|
37
|
+
const midnightBookBestFirst = (side) => (side === 'asks' ? -1 : 1);
|
|
38
|
+
exports.midnightBookBestFirst = midnightBookBestFirst;
|
|
39
|
+
const buildMidnightParsedBook = (offers, side) => {
|
|
40
|
+
const bestFirst = [...offers].sort((a, b) => new decimal_js_1.default(a.rate).minus(b.rate).mul((0, exports.midnightBookBestFirst)(side)).toNumber());
|
|
41
|
+
if (bestFirst.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
return {
|
|
44
|
+
bestRate: bestFirst[0].rate,
|
|
45
|
+
totalLiquidity: bestFirst.reduce((sum, offer) => sum.add(offer.liquidity), new decimal_js_1.default(0)).toString(),
|
|
46
|
+
offers: bestFirst,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.buildMidnightParsedBook = buildMidnightParsedBook;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import Dec from 'decimal.js';
|
|
2
|
+
import { MorphoMidnightBookSide, MorphoMidnightMarketData, MorphoMidnightParsedBook, NetworkNumber } from '../../types';
|
|
3
|
+
import type { MorphoMidnightBorrowQuote, MorphoMidnightPaybackQuote, MorphoMidnightPaybackUnitsQuote } from './index';
|
|
4
|
+
type TenorBookKey = 'asks' | 'bids';
|
|
5
|
+
export declare const tenorBookKeyFor: (side: MorphoMidnightBookSide) => TenorBookKey;
|
|
6
|
+
export declare const tenorBookRateToApyPercent: (rate: Dec.Value) => string;
|
|
7
|
+
export declare const tenorCapPrice: (bestPrice: string, slippagePercent: Dec.Value, direction: 1 | -1, ttmDays: Dec.Value, boundRate?: Dec.Value) => string;
|
|
8
|
+
interface TenorOfferCollateral {
|
|
9
|
+
token: string;
|
|
10
|
+
lltv: string | number;
|
|
11
|
+
liquidation_cursor: string | number;
|
|
12
|
+
oracle: string;
|
|
13
|
+
}
|
|
14
|
+
interface TenorOffer {
|
|
15
|
+
start: string | number;
|
|
16
|
+
group?: string;
|
|
17
|
+
callback?: string;
|
|
18
|
+
tick: string | number;
|
|
19
|
+
chain_id: string | number;
|
|
20
|
+
maturity: string | number;
|
|
21
|
+
buy: boolean;
|
|
22
|
+
maker: string;
|
|
23
|
+
loan_token_address: string;
|
|
24
|
+
callback_data?: string;
|
|
25
|
+
expiry: string | number;
|
|
26
|
+
ratifier?: string;
|
|
27
|
+
collaterals: TenorOfferCollateral[];
|
|
28
|
+
continuous_fee_cap: string | number;
|
|
29
|
+
enter_gate: string;
|
|
30
|
+
liquidator_gate: string;
|
|
31
|
+
max_assets: string | number;
|
|
32
|
+
max_units: string | number;
|
|
33
|
+
ratifier_data?: string;
|
|
34
|
+
rcf_threshold: string | number;
|
|
35
|
+
receiver_if_maker_is_seller?: string;
|
|
36
|
+
reduce_only: boolean;
|
|
37
|
+
}
|
|
38
|
+
interface TenorOfferFill {
|
|
39
|
+
units: string | number;
|
|
40
|
+
offer: TenorOffer;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Tenor's offer JSON is flat (market fields live on the offer). Morpho's is nested, and that nested
|
|
44
|
+
* shape is what the app encodes for `Midnight.take`. Map Tenor into that shape so recipes stay on one encoder.
|
|
45
|
+
*/
|
|
46
|
+
export declare const tenorOfferToApiOffer: (offer: TenorOffer) => {
|
|
47
|
+
market: {
|
|
48
|
+
chain_id: string | number;
|
|
49
|
+
midnight: "0xAdedD8ab6dE832766Fedf0FaC4992E5C4D3EA18A";
|
|
50
|
+
loan_token: string;
|
|
51
|
+
collaterals: TenorOfferCollateral[];
|
|
52
|
+
maturity: string | number;
|
|
53
|
+
rcf_threshold: string | number;
|
|
54
|
+
enter_gate: string;
|
|
55
|
+
liquidator_gate: string;
|
|
56
|
+
};
|
|
57
|
+
buy: boolean;
|
|
58
|
+
maker: string;
|
|
59
|
+
start: string | number;
|
|
60
|
+
expiry: string | number;
|
|
61
|
+
tick: string | number;
|
|
62
|
+
group: string;
|
|
63
|
+
callback: string;
|
|
64
|
+
callback_data: string;
|
|
65
|
+
receiver_if_maker_is_seller: string;
|
|
66
|
+
ratifier: string;
|
|
67
|
+
reduce_only: boolean;
|
|
68
|
+
max_units: string | number;
|
|
69
|
+
max_assets: string | number;
|
|
70
|
+
continuous_fee_cap: string | number;
|
|
71
|
+
};
|
|
72
|
+
export declare const tenorOfferFillToApiFill: (fill: TenorOfferFill) => {
|
|
73
|
+
units: string | number;
|
|
74
|
+
offer: {
|
|
75
|
+
market: {
|
|
76
|
+
chain_id: string | number;
|
|
77
|
+
midnight: "0xAdedD8ab6dE832766Fedf0FaC4992E5C4D3EA18A";
|
|
78
|
+
loan_token: string;
|
|
79
|
+
collaterals: TenorOfferCollateral[];
|
|
80
|
+
maturity: string | number;
|
|
81
|
+
rcf_threshold: string | number;
|
|
82
|
+
enter_gate: string;
|
|
83
|
+
liquidator_gate: string;
|
|
84
|
+
};
|
|
85
|
+
buy: boolean;
|
|
86
|
+
maker: string;
|
|
87
|
+
start: string | number;
|
|
88
|
+
expiry: string | number;
|
|
89
|
+
tick: string | number;
|
|
90
|
+
group: string;
|
|
91
|
+
callback: string;
|
|
92
|
+
callback_data: string;
|
|
93
|
+
receiver_if_maker_is_seller: string;
|
|
94
|
+
ratifier: string;
|
|
95
|
+
reduce_only: boolean;
|
|
96
|
+
max_units: string | number;
|
|
97
|
+
max_assets: string | number;
|
|
98
|
+
continuous_fee_cap: string | number;
|
|
99
|
+
};
|
|
100
|
+
ratifier_data: string;
|
|
101
|
+
market_id: string;
|
|
102
|
+
};
|
|
103
|
+
interface TenorBookBucket {
|
|
104
|
+
rate: number | string;
|
|
105
|
+
liquidity: number | string;
|
|
106
|
+
cumulative_liquidity?: number | string;
|
|
107
|
+
}
|
|
108
|
+
interface TenorBookSidePayload {
|
|
109
|
+
buckets?: TenorBookBucket[];
|
|
110
|
+
}
|
|
111
|
+
interface TenorBookResponse {
|
|
112
|
+
asks?: TenorBookSidePayload | TenorBookBucket[];
|
|
113
|
+
bids?: TenorBookSidePayload | TenorBookBucket[];
|
|
114
|
+
}
|
|
115
|
+
/** The levels resting on the Tenor side a taker of `side` fills, in raw loan-token base units. */
|
|
116
|
+
export declare const parseTenorBookSide: (json: TenorBookResponse, side: MorphoMidnightBookSide) => {
|
|
117
|
+
rate: string;
|
|
118
|
+
liquidityRaw: string;
|
|
119
|
+
}[];
|
|
120
|
+
export declare const parseTenorOrderBook: (json: TenorBookResponse, side: MorphoMidnightBookSide, loanSymbol: string) => MorphoMidnightParsedBook | null;
|
|
121
|
+
export declare const getTenorMarketBook: (market: MorphoMidnightMarketData, network: NetworkNumber, side?: MorphoMidnightBookSide) => Promise<MorphoMidnightParsedBook | null>;
|
|
122
|
+
export declare const getTenorBorrowQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, maxBorrowRate?: Dec.Value, taker?: string, network?: NetworkNumber) => Promise<MorphoMidnightBorrowQuote>;
|
|
123
|
+
export declare const getTenorPaybackQuote: (marketId: string, assetsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value, taker?: string, network?: NetworkNumber) => Promise<MorphoMidnightPaybackQuote>;
|
|
124
|
+
export declare const getTenorPaybackUnitsQuote: (marketId: string, unitsRaw: string, slippagePercent: Dec.Value, maturity: number, minPaybackRate?: Dec.Value, taker?: string, network?: NetworkNumber) => Promise<MorphoMidnightPaybackUnitsQuote>;
|
|
125
|
+
export {};
|