@defisaver/positions-sdk 2.1.127-midnight-12-dev → 2.1.127-midnight-13-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 +2 -1
- package/cjs/helpers/morphoMidnightHelpers/index.js +3 -1
- package/cjs/morphoMidnight/index.js +31 -13
- package/cjs/types/morphoMidnight.d.ts +19 -0
- package/cjs/types/morphoMidnight.js +20 -1
- package/esm/helpers/morphoMidnightHelpers/index.d.ts +2 -1
- package/esm/helpers/morphoMidnightHelpers/index.js +1 -0
- package/esm/morphoMidnight/index.js +32 -14
- package/esm/types/morphoMidnight.d.ts +19 -0
- package/esm/types/morphoMidnight.js +19 -0
- package/package.json +1 -1
- package/src/helpers/morphoMidnightHelpers/index.ts +6 -2
- package/src/morphoMidnight/index.ts +31 -16
- package/src/types/morphoMidnight.ts +20 -3
|
@@ -64,6 +64,7 @@ export interface MorphoMidnightPaybackUnitsQuote {
|
|
|
64
64
|
* Rounded **down**, since a wider slippage is a looser cap than the caller asked for.
|
|
65
65
|
*/
|
|
66
66
|
export declare const midnightSlippageParam: (slippagePercent: Dec.Value) => string;
|
|
67
|
+
export declare const morphoMidnightMarketReportsBorrowInfo: (market: Pick<MorphoMidnightMarketData, "curator"> | string) => boolean;
|
|
67
68
|
/**
|
|
68
69
|
* Current borrower rate + debt breakdown from the Midnight positions API. Reconstructing this from the raw
|
|
69
70
|
* `/transactions` fill history only sums `borrow` fills, so it overstates debt for any position with an
|
|
@@ -91,7 +92,7 @@ export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId
|
|
|
91
92
|
* it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
|
|
92
93
|
* rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
|
|
93
94
|
*/
|
|
94
|
-
export declare const scaleMorphoMidnightDebtSplit:
|
|
95
|
+
export declare const scaleMorphoMidnightDebtSplit: ({ debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
|
|
95
96
|
/**
|
|
96
97
|
* One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
|
|
97
98
|
* prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
|
|
@@ -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.scaleMorphoMidnightDebtSplit = exports.getMorphoMidnightUserBorrowInfo = exports.midnightSlippageParam = exports.getMorphoMidnightAggregatedPositionData = exports.tenorOfferToApiOffer = exports.tenorOfferFillToApiFill = exports.tenorBookRateToApyPercent = exports.tenorBookKeyFor = exports.MIDNIGHT_DEFAULT_RATE_SLIPPAGE = exports.midnightTimeToMaturityDays = exports.midnightPriceFromApy = exports.midnightBoundPrice = exports.midnightBookBestFirst = exports.midnightApyFromPrice = exports.buildMidnightParsedBook = void 0;
|
|
15
|
+
exports.getMorphoMidnightPaybackUnitsQuote = exports.getMorphoMidnightPaybackQuote = exports.getMorphoMidnightBorrowQuote = exports.getMorphoMidnightMarketBook = exports.scaleMorphoMidnightDebtSplit = exports.getMorphoMidnightUserBorrowInfo = exports.morphoMidnightMarketReportsBorrowInfo = exports.midnightSlippageParam = exports.getMorphoMidnightAggregatedPositionData = exports.tenorOfferToApiOffer = exports.tenorOfferFillToApiFill = exports.tenorBookRateToApyPercent = exports.tenorBookKeyFor = exports.MIDNIGHT_DEFAULT_RATE_SLIPPAGE = exports.midnightTimeToMaturityDays = exports.midnightPriceFromApy = exports.midnightBoundPrice = 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");
|
|
@@ -123,6 +123,8 @@ const MIDNIGHT_SLIPPAGE_MAX = 100;
|
|
|
123
123
|
*/
|
|
124
124
|
const midnightSlippageParam = (slippagePercent) => decimal_js_1.default.min(decimal_js_1.default.max(new decimal_js_1.default(slippagePercent), MIDNIGHT_SLIPPAGE_MIN), MIDNIGHT_SLIPPAGE_MAX).toDP(1, decimal_js_1.default.ROUND_DOWN).toString();
|
|
125
125
|
exports.midnightSlippageParam = midnightSlippageParam;
|
|
126
|
+
const morphoMidnightMarketReportsBorrowInfo = (market) => (!(0, morphoMidnight_1.isTenorMidnightMarket)(market));
|
|
127
|
+
exports.morphoMidnightMarketReportsBorrowInfo = morphoMidnightMarketReportsBorrowInfo;
|
|
126
128
|
/**
|
|
127
129
|
* Current borrower rate + debt breakdown from the Midnight positions API. Reconstructing this from the raw
|
|
128
130
|
* `/transactions` fill history only sums `borrow` fills, so it overstates debt for any position with an
|
|
@@ -22,6 +22,7 @@ const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
|
22
22
|
const tokens_1 = require("@defisaver/tokens");
|
|
23
23
|
const common_1 = require("../types/common");
|
|
24
24
|
const contracts_1 = require("../contracts");
|
|
25
|
+
const types_1 = require("../types");
|
|
25
26
|
const constants_1 = require("../constants");
|
|
26
27
|
const staking_1 = require("../staking");
|
|
27
28
|
const utils_1 = require("../services/utils");
|
|
@@ -165,21 +166,37 @@ function _getMorphoMidnightAccountData(provider, network, account, selectedMarke
|
|
|
165
166
|
let borrowRate = '0';
|
|
166
167
|
let debtBase = debt; // fallback: treat the full on-chain debt as principal until fill history is known
|
|
167
168
|
let debtInterest = '0';
|
|
169
|
+
let borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Available;
|
|
168
170
|
let assetsDataForApy = marketInfo.assetsData;
|
|
169
171
|
if (new decimal_js_1.default(positionInfo.debt.toString()).gt(0)) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (new decimal_js_1.default(borrowInfo.debtTotal).gt(0)) {
|
|
173
|
-
borrowRate = borrowInfo.borrowRate;
|
|
174
|
-
debtBase = borrowInfo.debtBase;
|
|
175
|
-
debtInterest = borrowInfo.debtInterest;
|
|
176
|
-
usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
|
|
177
|
-
// Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
|
|
178
|
-
assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
|
|
179
|
-
}
|
|
172
|
+
if (!(0, morphoMidnightHelpers_1.morphoMidnightMarketReportsBorrowInfo)(selectedMarket)) {
|
|
173
|
+
borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Unavailable;
|
|
180
174
|
}
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
else {
|
|
176
|
+
try {
|
|
177
|
+
const borrowInfo = yield (0, morphoMidnightHelpers_1.getMorphoMidnightUserBorrowInfo)(account, marketId, marketInfo.loanToken);
|
|
178
|
+
if (new decimal_js_1.default(borrowInfo.debtTotal).gt(0)) {
|
|
179
|
+
borrowRate = borrowInfo.borrowRate;
|
|
180
|
+
debtBase = borrowInfo.debtBase;
|
|
181
|
+
debtInterest = borrowInfo.debtInterest;
|
|
182
|
+
usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
|
|
183
|
+
// Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
|
|
184
|
+
assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
|
|
185
|
+
const describesChainDebt = new decimal_js_1.default(borrowInfo.debtTotal).eq(debt);
|
|
186
|
+
const ratePriced = new decimal_js_1.default(borrowRate).gt(0) || new decimal_js_1.default(debtInterest).lte(0);
|
|
187
|
+
borrowInfoStatus = describesChainDebt && ratePriced
|
|
188
|
+
? types_1.MorphoMidnightBorrowInfoStatus.Available
|
|
189
|
+
: types_1.MorphoMidnightBorrowInfoStatus.Pending;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// No entry for the position: the API does not know it yet, rather than it having no principal.
|
|
193
|
+
borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Pending;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
// Positions API unreachable — the fallback above still renders, and the next call may succeed.
|
|
198
|
+
borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Pending;
|
|
199
|
+
}
|
|
183
200
|
}
|
|
184
201
|
}
|
|
185
202
|
return Object.assign({ usedAssets,
|
|
@@ -187,7 +204,8 @@ function _getMorphoMidnightAccountData(provider, network, account, selectedMarke
|
|
|
187
204
|
debt,
|
|
188
205
|
borrowRate,
|
|
189
206
|
debtBase,
|
|
190
|
-
debtInterest,
|
|
207
|
+
debtInterest,
|
|
208
|
+
borrowInfoStatus, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, (0, morphoMidnightHelpers_1.getMorphoMidnightAggregatedPositionData)({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
|
|
191
209
|
});
|
|
192
210
|
}
|
|
193
211
|
function getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
|
|
@@ -113,6 +113,24 @@ export interface MorphoMidnightAggregatedPositionData {
|
|
|
113
113
|
collLiquidationRatio?: string;
|
|
114
114
|
exposure: string;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* How much weight `borrowRate` / `debtBase` / `debtInterest` carry on a given position. They fall back to
|
|
118
|
+
* `'0'` / `debt` / `'0'`, which is indistinguishable from a real 0%-interest position, so anything
|
|
119
|
+
* displaying them has to read this to know whether it is looking at a number or at a placeholder.
|
|
120
|
+
*
|
|
121
|
+
* - `Available` — reported and reconciled against the on-chain debt (also lenders and debt-free positions,
|
|
122
|
+
* which have nothing to report).
|
|
123
|
+
* - `Pending` — the indexer has not caught up with the chain yet: it does not know the position, or its
|
|
124
|
+
* split describes a different debt. Refetching resolves it; `getMorphoMidnightUserBorrowInfo` failing
|
|
125
|
+
* outright lands here too, since the next call may well succeed.
|
|
126
|
+
* - `Unavailable` — no source covers this market, so refetching changes nothing. See
|
|
127
|
+
* `morphoMidnightMarketReportsBorrowInfo`.
|
|
128
|
+
*/
|
|
129
|
+
export declare enum MorphoMidnightBorrowInfoStatus {
|
|
130
|
+
Available = "available",
|
|
131
|
+
Pending = "pending",
|
|
132
|
+
Unavailable = "unavailable"
|
|
133
|
+
}
|
|
116
134
|
export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
|
|
117
135
|
usedAssets: MMUsedAssets;
|
|
118
136
|
credit: string;
|
|
@@ -120,6 +138,7 @@ export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPosi
|
|
|
120
138
|
borrowRate: string;
|
|
121
139
|
debtBase: string;
|
|
122
140
|
debtInterest: string;
|
|
141
|
+
borrowInfoStatus: MorphoMidnightBorrowInfoStatus;
|
|
123
142
|
maturity: number;
|
|
124
143
|
isMatured: boolean;
|
|
125
144
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MorphoMidnightVersions = void 0;
|
|
3
|
+
exports.MorphoMidnightBorrowInfoStatus = exports.MorphoMidnightVersions = void 0;
|
|
4
4
|
var MorphoMidnightVersions;
|
|
5
5
|
(function (MorphoMidnightVersions) {
|
|
6
6
|
// BASE
|
|
@@ -29,3 +29,22 @@ var MorphoMidnightVersions;
|
|
|
29
29
|
MorphoMidnightVersions["MorphoMidnightTenorCbETHWETH_20261119_Base"] = "morphomidnighttenorcbethweth_20261119_base";
|
|
30
30
|
MorphoMidnightVersions["MorphoMidnightTenorCbETHWETH_20261217_Base"] = "morphomidnighttenorcbethweth_20261217_base";
|
|
31
31
|
})(MorphoMidnightVersions || (exports.MorphoMidnightVersions = MorphoMidnightVersions = {}));
|
|
32
|
+
/**
|
|
33
|
+
* How much weight `borrowRate` / `debtBase` / `debtInterest` carry on a given position. They fall back to
|
|
34
|
+
* `'0'` / `debt` / `'0'`, which is indistinguishable from a real 0%-interest position, so anything
|
|
35
|
+
* displaying them has to read this to know whether it is looking at a number or at a placeholder.
|
|
36
|
+
*
|
|
37
|
+
* - `Available` — reported and reconciled against the on-chain debt (also lenders and debt-free positions,
|
|
38
|
+
* which have nothing to report).
|
|
39
|
+
* - `Pending` — the indexer has not caught up with the chain yet: it does not know the position, or its
|
|
40
|
+
* split describes a different debt. Refetching resolves it; `getMorphoMidnightUserBorrowInfo` failing
|
|
41
|
+
* outright lands here too, since the next call may well succeed.
|
|
42
|
+
* - `Unavailable` — no source covers this market, so refetching changes nothing. See
|
|
43
|
+
* `morphoMidnightMarketReportsBorrowInfo`.
|
|
44
|
+
*/
|
|
45
|
+
var MorphoMidnightBorrowInfoStatus;
|
|
46
|
+
(function (MorphoMidnightBorrowInfoStatus) {
|
|
47
|
+
MorphoMidnightBorrowInfoStatus["Available"] = "available";
|
|
48
|
+
MorphoMidnightBorrowInfoStatus["Pending"] = "pending";
|
|
49
|
+
MorphoMidnightBorrowInfoStatus["Unavailable"] = "unavailable";
|
|
50
|
+
})(MorphoMidnightBorrowInfoStatus || (exports.MorphoMidnightBorrowInfoStatus = MorphoMidnightBorrowInfoStatus = {}));
|
|
@@ -64,6 +64,7 @@ export interface MorphoMidnightPaybackUnitsQuote {
|
|
|
64
64
|
* Rounded **down**, since a wider slippage is a looser cap than the caller asked for.
|
|
65
65
|
*/
|
|
66
66
|
export declare const midnightSlippageParam: (slippagePercent: Dec.Value) => string;
|
|
67
|
+
export declare const morphoMidnightMarketReportsBorrowInfo: (market: Pick<MorphoMidnightMarketData, "curator"> | string) => boolean;
|
|
67
68
|
/**
|
|
68
69
|
* Current borrower rate + debt breakdown from the Midnight positions API. Reconstructing this from the raw
|
|
69
70
|
* `/transactions` fill history only sums `borrow` fills, so it overstates debt for any position with an
|
|
@@ -91,7 +92,7 @@ export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId
|
|
|
91
92
|
* it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
|
|
92
93
|
* rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
|
|
93
94
|
*/
|
|
94
|
-
export declare const scaleMorphoMidnightDebtSplit:
|
|
95
|
+
export declare const scaleMorphoMidnightDebtSplit: ({ debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
|
|
95
96
|
/**
|
|
96
97
|
* One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
|
|
97
98
|
* prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
|
|
@@ -104,6 +104,7 @@ const MIDNIGHT_SLIPPAGE_MAX = 100;
|
|
|
104
104
|
* Rounded **down**, since a wider slippage is a looser cap than the caller asked for.
|
|
105
105
|
*/
|
|
106
106
|
export const midnightSlippageParam = (slippagePercent) => Dec.min(Dec.max(new Dec(slippagePercent), MIDNIGHT_SLIPPAGE_MIN), MIDNIGHT_SLIPPAGE_MAX).toDP(1, Dec.ROUND_DOWN).toString();
|
|
107
|
+
export const morphoMidnightMarketReportsBorrowInfo = (market) => (!isTenorMidnightMarket(market));
|
|
107
108
|
/**
|
|
108
109
|
* Current borrower rate + debt breakdown from the Midnight positions API. Reconstructing this from the raw
|
|
109
110
|
* `/transactions` fill history only sums `borrow` fills, so it overstates debt for any position with an
|
|
@@ -11,10 +11,11 @@ import Dec from 'decimal.js';
|
|
|
11
11
|
import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
12
12
|
import { NetworkNumber, } from '../types/common';
|
|
13
13
|
import { DFSFeedRegistryContractViem, FeedRegistryContractViem, MorphoMidnightViewContractViem, } from '../contracts';
|
|
14
|
+
import { MorphoMidnightBorrowInfoStatus, } from '../types';
|
|
14
15
|
import { USD_QUOTE } from '../constants';
|
|
15
16
|
import { calculateNetApy } from '../staking';
|
|
16
17
|
import { isMainnetNetwork, wethToEth } from '../services/utils';
|
|
17
|
-
import { getMorphoMidnightAggregatedPositionData, getMorphoMidnightUserBorrowInfo } from '../helpers/morphoMidnightHelpers';
|
|
18
|
+
import { getMorphoMidnightAggregatedPositionData, getMorphoMidnightUserBorrowInfo, morphoMidnightMarketReportsBorrowInfo } from '../helpers/morphoMidnightHelpers';
|
|
18
19
|
import { getChainlinkAssetAddress } from '../services/priceService';
|
|
19
20
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
20
21
|
const HARDCODED_USD_STABLE_PRICE = '100000000'; // $1 with 8 decimals
|
|
@@ -154,21 +155,37 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
|
|
|
154
155
|
let borrowRate = '0';
|
|
155
156
|
let debtBase = debt; // fallback: treat the full on-chain debt as principal until fill history is known
|
|
156
157
|
let debtInterest = '0';
|
|
158
|
+
let borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Available;
|
|
157
159
|
let assetsDataForApy = marketInfo.assetsData;
|
|
158
160
|
if (new Dec(positionInfo.debt.toString()).gt(0)) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (new Dec(borrowInfo.debtTotal).gt(0)) {
|
|
162
|
-
borrowRate = borrowInfo.borrowRate;
|
|
163
|
-
debtBase = borrowInfo.debtBase;
|
|
164
|
-
debtInterest = borrowInfo.debtInterest;
|
|
165
|
-
usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
|
|
166
|
-
// Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
|
|
167
|
-
assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
|
|
168
|
-
}
|
|
161
|
+
if (!morphoMidnightMarketReportsBorrowInfo(selectedMarket)) {
|
|
162
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Unavailable;
|
|
169
163
|
}
|
|
170
|
-
|
|
171
|
-
|
|
164
|
+
else {
|
|
165
|
+
try {
|
|
166
|
+
const borrowInfo = yield getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
|
|
167
|
+
if (new Dec(borrowInfo.debtTotal).gt(0)) {
|
|
168
|
+
borrowRate = borrowInfo.borrowRate;
|
|
169
|
+
debtBase = borrowInfo.debtBase;
|
|
170
|
+
debtInterest = borrowInfo.debtInterest;
|
|
171
|
+
usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
|
|
172
|
+
// Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
|
|
173
|
+
assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
|
|
174
|
+
const describesChainDebt = new Dec(borrowInfo.debtTotal).eq(debt);
|
|
175
|
+
const ratePriced = new Dec(borrowRate).gt(0) || new Dec(debtInterest).lte(0);
|
|
176
|
+
borrowInfoStatus = describesChainDebt && ratePriced
|
|
177
|
+
? MorphoMidnightBorrowInfoStatus.Available
|
|
178
|
+
: MorphoMidnightBorrowInfoStatus.Pending;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// No entry for the position: the API does not know it yet, rather than it having no principal.
|
|
182
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
// Positions API unreachable — the fallback above still renders, and the next call may succeed.
|
|
187
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
|
|
188
|
+
}
|
|
172
189
|
}
|
|
173
190
|
}
|
|
174
191
|
return Object.assign({ usedAssets,
|
|
@@ -176,7 +193,8 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
|
|
|
176
193
|
debt,
|
|
177
194
|
borrowRate,
|
|
178
195
|
debtBase,
|
|
179
|
-
debtInterest,
|
|
196
|
+
debtInterest,
|
|
197
|
+
borrowInfoStatus, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
|
|
180
198
|
});
|
|
181
199
|
}
|
|
182
200
|
export function getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
|
|
@@ -113,6 +113,24 @@ export interface MorphoMidnightAggregatedPositionData {
|
|
|
113
113
|
collLiquidationRatio?: string;
|
|
114
114
|
exposure: string;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* How much weight `borrowRate` / `debtBase` / `debtInterest` carry on a given position. They fall back to
|
|
118
|
+
* `'0'` / `debt` / `'0'`, which is indistinguishable from a real 0%-interest position, so anything
|
|
119
|
+
* displaying them has to read this to know whether it is looking at a number or at a placeholder.
|
|
120
|
+
*
|
|
121
|
+
* - `Available` — reported and reconciled against the on-chain debt (also lenders and debt-free positions,
|
|
122
|
+
* which have nothing to report).
|
|
123
|
+
* - `Pending` — the indexer has not caught up with the chain yet: it does not know the position, or its
|
|
124
|
+
* split describes a different debt. Refetching resolves it; `getMorphoMidnightUserBorrowInfo` failing
|
|
125
|
+
* outright lands here too, since the next call may well succeed.
|
|
126
|
+
* - `Unavailable` — no source covers this market, so refetching changes nothing. See
|
|
127
|
+
* `morphoMidnightMarketReportsBorrowInfo`.
|
|
128
|
+
*/
|
|
129
|
+
export declare enum MorphoMidnightBorrowInfoStatus {
|
|
130
|
+
Available = "available",
|
|
131
|
+
Pending = "pending",
|
|
132
|
+
Unavailable = "unavailable"
|
|
133
|
+
}
|
|
116
134
|
export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
|
|
117
135
|
usedAssets: MMUsedAssets;
|
|
118
136
|
credit: string;
|
|
@@ -120,6 +138,7 @@ export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPosi
|
|
|
120
138
|
borrowRate: string;
|
|
121
139
|
debtBase: string;
|
|
122
140
|
debtInterest: string;
|
|
141
|
+
borrowInfoStatus: MorphoMidnightBorrowInfoStatus;
|
|
123
142
|
maturity: number;
|
|
124
143
|
isMatured: boolean;
|
|
125
144
|
}
|
|
@@ -26,3 +26,22 @@ export var MorphoMidnightVersions;
|
|
|
26
26
|
MorphoMidnightVersions["MorphoMidnightTenorCbETHWETH_20261119_Base"] = "morphomidnighttenorcbethweth_20261119_base";
|
|
27
27
|
MorphoMidnightVersions["MorphoMidnightTenorCbETHWETH_20261217_Base"] = "morphomidnighttenorcbethweth_20261217_base";
|
|
28
28
|
})(MorphoMidnightVersions || (MorphoMidnightVersions = {}));
|
|
29
|
+
/**
|
|
30
|
+
* How much weight `borrowRate` / `debtBase` / `debtInterest` carry on a given position. They fall back to
|
|
31
|
+
* `'0'` / `debt` / `'0'`, which is indistinguishable from a real 0%-interest position, so anything
|
|
32
|
+
* displaying them has to read this to know whether it is looking at a number or at a placeholder.
|
|
33
|
+
*
|
|
34
|
+
* - `Available` — reported and reconciled against the on-chain debt (also lenders and debt-free positions,
|
|
35
|
+
* which have nothing to report).
|
|
36
|
+
* - `Pending` — the indexer has not caught up with the chain yet: it does not know the position, or its
|
|
37
|
+
* split describes a different debt. Refetching resolves it; `getMorphoMidnightUserBorrowInfo` failing
|
|
38
|
+
* outright lands here too, since the next call may well succeed.
|
|
39
|
+
* - `Unavailable` — no source covers this market, so refetching changes nothing. See
|
|
40
|
+
* `morphoMidnightMarketReportsBorrowInfo`.
|
|
41
|
+
*/
|
|
42
|
+
export var MorphoMidnightBorrowInfoStatus;
|
|
43
|
+
(function (MorphoMidnightBorrowInfoStatus) {
|
|
44
|
+
MorphoMidnightBorrowInfoStatus["Available"] = "available";
|
|
45
|
+
MorphoMidnightBorrowInfoStatus["Pending"] = "pending";
|
|
46
|
+
MorphoMidnightBorrowInfoStatus["Unavailable"] = "unavailable";
|
|
47
|
+
})(MorphoMidnightBorrowInfoStatus || (MorphoMidnightBorrowInfoStatus = {}));
|
package/package.json
CHANGED
|
@@ -227,6 +227,10 @@ export const midnightSlippageParam = (slippagePercent: Dec.Value): string => Dec
|
|
|
227
227
|
MIDNIGHT_SLIPPAGE_MAX,
|
|
228
228
|
).toDP(1, Dec.ROUND_DOWN).toString();
|
|
229
229
|
|
|
230
|
+
export const morphoMidnightMarketReportsBorrowInfo = (market: Pick<MorphoMidnightMarketData, 'curator'> | string): boolean => (
|
|
231
|
+
!isTenorMidnightMarket(market)
|
|
232
|
+
);
|
|
233
|
+
|
|
230
234
|
/**
|
|
231
235
|
* Current borrower rate + debt breakdown from the Midnight positions API. Reconstructing this from the raw
|
|
232
236
|
* `/transactions` fill history only sums `borrow` fills, so it overstates debt for any position with an
|
|
@@ -273,8 +277,8 @@ export const getMorphoMidnightUserBorrowInfo = async (
|
|
|
273
277
|
* it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
|
|
274
278
|
* rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
|
|
275
279
|
*/
|
|
276
|
-
export const scaleMorphoMidnightDebtSplit =
|
|
277
|
-
{ debtBase, debtInterest }:
|
|
280
|
+
export const scaleMorphoMidnightDebtSplit = (
|
|
281
|
+
{ debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'>,
|
|
278
282
|
borrowedBefore: Dec.Value,
|
|
279
283
|
borrowedAfter: Dec.Value,
|
|
280
284
|
): Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'> => {
|
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
DFSFeedRegistryContractViem, FeedRegistryContractViem, MorphoMidnightViewContractViem,
|
|
9
9
|
} from '../contracts';
|
|
10
10
|
import {
|
|
11
|
-
MorphoMidnightAssetsData, MorphoMidnightMarketData, MorphoMidnightMarketInfo, MorphoMidnightPositionData,
|
|
11
|
+
MorphoMidnightAssetsData, MorphoMidnightBorrowInfoStatus, MorphoMidnightMarketData, MorphoMidnightMarketInfo, MorphoMidnightPositionData,
|
|
12
12
|
} from '../types';
|
|
13
13
|
import { USD_QUOTE } from '../constants';
|
|
14
14
|
import { calculateNetApy } from '../staking';
|
|
15
15
|
import { isMainnetNetwork, wethToEth } from '../services/utils';
|
|
16
|
-
import { getMorphoMidnightAggregatedPositionData, getMorphoMidnightUserBorrowInfo } from '../helpers/morphoMidnightHelpers';
|
|
16
|
+
import { getMorphoMidnightAggregatedPositionData, getMorphoMidnightUserBorrowInfo, morphoMidnightMarketReportsBorrowInfo } from '../helpers/morphoMidnightHelpers';
|
|
17
17
|
import { getChainlinkAssetAddress } from '../services/priceService';
|
|
18
18
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
19
19
|
|
|
@@ -163,23 +163,37 @@ export async function _getMorphoMidnightAccountData(provider: Client, network: N
|
|
|
163
163
|
let borrowRate = '0';
|
|
164
164
|
let debtBase = debt; // fallback: treat the full on-chain debt as principal until fill history is known
|
|
165
165
|
let debtInterest = '0';
|
|
166
|
+
let borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Available;
|
|
166
167
|
let assetsDataForApy = marketInfo.assetsData;
|
|
167
168
|
if (new Dec(positionInfo.debt.toString()).gt(0)) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
169
|
+
if (!morphoMidnightMarketReportsBorrowInfo(selectedMarket)) {
|
|
170
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Unavailable;
|
|
171
|
+
} else {
|
|
172
|
+
try {
|
|
173
|
+
const borrowInfo = await getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
|
|
174
|
+
if (new Dec(borrowInfo.debtTotal).gt(0)) {
|
|
175
|
+
borrowRate = borrowInfo.borrowRate;
|
|
176
|
+
debtBase = borrowInfo.debtBase;
|
|
177
|
+
debtInterest = borrowInfo.debtInterest;
|
|
178
|
+
usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
|
|
179
|
+
// Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
|
|
180
|
+
assetsDataForApy = {
|
|
181
|
+
...marketInfo.assetsData,
|
|
182
|
+
[marketInfo.loanToken]: { ...loanTokenData, borrowRate },
|
|
183
|
+
};
|
|
184
|
+
const describesChainDebt = new Dec(borrowInfo.debtTotal).eq(debt);
|
|
185
|
+
const ratePriced = new Dec(borrowRate).gt(0) || new Dec(debtInterest).lte(0);
|
|
186
|
+
borrowInfoStatus = describesChainDebt && ratePriced
|
|
187
|
+
? MorphoMidnightBorrowInfoStatus.Available
|
|
188
|
+
: MorphoMidnightBorrowInfoStatus.Pending;
|
|
189
|
+
} else {
|
|
190
|
+
// No entry for the position: the API does not know it yet, rather than it having no principal.
|
|
191
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
// Positions API unreachable — the fallback above still renders, and the next call may succeed.
|
|
195
|
+
borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
|
|
180
196
|
}
|
|
181
|
-
} catch (err) {
|
|
182
|
-
// Orderbook API unavailable — keep the on-chain-only fallback above.
|
|
183
197
|
}
|
|
184
198
|
}
|
|
185
199
|
|
|
@@ -190,6 +204,7 @@ export async function _getMorphoMidnightAccountData(provider: Client, network: N
|
|
|
190
204
|
borrowRate,
|
|
191
205
|
debtBase,
|
|
192
206
|
debtInterest,
|
|
207
|
+
borrowInfoStatus,
|
|
193
208
|
maturity: marketInfo.maturity,
|
|
194
209
|
isMatured: marketInfo.isMatured,
|
|
195
210
|
...getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }),
|
|
@@ -132,18 +132,35 @@ export interface MorphoMidnightAggregatedPositionData {
|
|
|
132
132
|
exposure: string,
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* How much weight `borrowRate` / `debtBase` / `debtInterest` carry on a given position. They fall back to
|
|
137
|
+
* `'0'` / `debt` / `'0'`, which is indistinguishable from a real 0%-interest position, so anything
|
|
138
|
+
* displaying them has to read this to know whether it is looking at a number or at a placeholder.
|
|
139
|
+
*
|
|
140
|
+
* - `Available` — reported and reconciled against the on-chain debt (also lenders and debt-free positions,
|
|
141
|
+
* which have nothing to report).
|
|
142
|
+
* - `Pending` — the indexer has not caught up with the chain yet: it does not know the position, or its
|
|
143
|
+
* split describes a different debt. Refetching resolves it; `getMorphoMidnightUserBorrowInfo` failing
|
|
144
|
+
* outright lands here too, since the next call may well succeed.
|
|
145
|
+
* - `Unavailable` — no source covers this market, so refetching changes nothing. See
|
|
146
|
+
* `morphoMidnightMarketReportsBorrowInfo`.
|
|
147
|
+
*/
|
|
148
|
+
export enum MorphoMidnightBorrowInfoStatus {
|
|
149
|
+
Available = 'available',
|
|
150
|
+
Pending = 'pending',
|
|
151
|
+
Unavailable = 'unavailable',
|
|
152
|
+
}
|
|
153
|
+
|
|
135
154
|
// Fixed-rate/YTM (derived from entry price + orderbook) is intentionally absent in MVP:
|
|
136
155
|
// MidnightView exposes no per-position rate, so a variable-MM-style APY would be misleading.
|
|
137
156
|
export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
|
|
138
157
|
usedAssets: MMUsedAssets,
|
|
139
158
|
credit: string, // lender credit units, face value at maturity (with interest); 0 for borrowers
|
|
140
159
|
debt: string, // borrower debt, face value at maturity (with interest); 0 for lenders
|
|
141
|
-
// Borrow rate + base/interest split are orderbook-derived off-chain (from the Midnight transactions API):
|
|
142
|
-
// MidnightView only stores `debt` (= face value at maturity), so principal-vs-interest and the effective
|
|
143
|
-
// rate are computed from the fill history. Default to '0'/`debt`/'0' for lenders or when the API is unavailable.
|
|
144
160
|
borrowRate: string, // weighted-average borrow APY as a percent
|
|
145
161
|
debtBase: string, // base borrowed (principal), loan-token units
|
|
146
162
|
debtInterest: string, // debt − debtBase (fixed interest owed at maturity), loan-token units
|
|
163
|
+
borrowInfoStatus: MorphoMidnightBorrowInfoStatus,
|
|
147
164
|
maturity: number,
|
|
148
165
|
isMatured: boolean,
|
|
149
166
|
}
|