@defisaver/positions-sdk 2.1.127-midnight-10-dev → 2.1.127-midnight-12-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.
@@ -74,6 +74,24 @@ export declare const midnightSlippageParam: (slippagePercent: Dec.Value) => stri
74
74
  * The caller swallows errors — a missing rate must never block position rendering.
75
75
  */
76
76
  export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId: string, loanTokenSymbol: string) => Promise<MorphoMidnightBorrowInfo>;
77
+ /**
78
+ * The inverse of the split above: where `getMorphoMidnightUserBorrowInfo` reads a position's principal and
79
+ * interest off the indexer, this carries that same split forward through a payback, from a debt of
80
+ * `borrowedBefore` down to one of `borrowedAfter`. Retiring units retires principal and interest pro rata,
81
+ * so both scale by the same fraction.
82
+ *
83
+ * Deriving the interest as `borrowedAfter − debtBase` instead reads it off two different sources —
84
+ * `borrowed` is the chain's debt, `debtBase` the indexer's principal — so the entire gap between them lands
85
+ * in the interest whenever they disagree, which they do until the indexer catches up with a fresh borrow or
86
+ * payback: behind a borrow it inflates the interest by the debt the indexer has not seen yet, behind a
87
+ * payback it goes negative on a position that still owes. Callers detect that window as
88
+ * `debtBase + debtInterest !== debt`.
89
+ *
90
+ * Pro rata is also what keeps the answer sane when a payback retires debt at a different rate than the one
91
+ * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
92
+ * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
93
+ */
94
+ export declare const scaleMorphoMidnightDebtSplit: <T extends Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">>({ debtBase, debtInterest }: T, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
77
95
  /**
78
96
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
79
97
  * 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.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.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");
@@ -54,6 +54,12 @@ const getMorphoMidnightAggregatedPositionData = ({ usedAssets, assetsData, marke
54
54
  // borrowLimit = Σ collateralUsd_i * lltv_i (per-collateral lltv carried on assetsData)
55
55
  payload.borrowLimitUsd = (0, moneymarket_1.getAssetsTotal)(usedAssets, ({ isSupplied, collateral }) => isSupplied && collateral, ({ symbol, suppliedUsd }) => { var _a; return new decimal_js_1.default(suppliedUsd).mul(((_a = assetsData[symbol]) === null || _a === void 0 ? void 0 : _a.lltv) || 0); });
56
56
  payload.liquidationLimitUsd = payload.borrowLimitUsd;
57
+ // Same subtraction every other money market uses, but it does NOT mean the same thing here. Elsewhere
58
+ // `borrowedUsd` is debt at present value, so the remainder is what a borrow would pay out. Midnight
59
+ // records debt at its face value at maturity, so this is face-value headroom: borrowing it would add
60
+ // more debt than the number says, by the market's discount. Anything surfacing this as "what you can
61
+ // borrow" has to scale it by the loan-per-unit price first (`midnightPriceFromApy` off a book rate) —
62
+ // a correction that grows with the term, past 7% on a one-year market.
57
63
  const leftToBorrowUsd = new decimal_js_1.default(payload.borrowLimitUsd).sub(payload.borrowedUsd);
58
64
  payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
59
65
  const loanTokenPrice = ((_a = assetsData[marketInfo.loanToken]) === null || _a === void 0 ? void 0 : _a.price) || '0';
@@ -140,6 +146,33 @@ const getMorphoMidnightUserBorrowInfo = (account, marketId, loanTokenSymbol) =>
140
146
  };
141
147
  });
142
148
  exports.getMorphoMidnightUserBorrowInfo = getMorphoMidnightUserBorrowInfo;
149
+ /**
150
+ * The inverse of the split above: where `getMorphoMidnightUserBorrowInfo` reads a position's principal and
151
+ * interest off the indexer, this carries that same split forward through a payback, from a debt of
152
+ * `borrowedBefore` down to one of `borrowedAfter`. Retiring units retires principal and interest pro rata,
153
+ * so both scale by the same fraction.
154
+ *
155
+ * Deriving the interest as `borrowedAfter − debtBase` instead reads it off two different sources —
156
+ * `borrowed` is the chain's debt, `debtBase` the indexer's principal — so the entire gap between them lands
157
+ * in the interest whenever they disagree, which they do until the indexer catches up with a fresh borrow or
158
+ * payback: behind a borrow it inflates the interest by the debt the indexer has not seen yet, behind a
159
+ * payback it goes negative on a position that still owes. Callers detect that window as
160
+ * `debtBase + debtInterest !== debt`.
161
+ *
162
+ * Pro rata is also what keeps the answer sane when a payback retires debt at a different rate than the one
163
+ * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
164
+ * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
165
+ */
166
+ const scaleMorphoMidnightDebtSplit = ({ debtBase, debtInterest }, borrowedBefore, borrowedAfter) => {
167
+ const fractionRemaining = new decimal_js_1.default(borrowedBefore).lte(0)
168
+ ? new decimal_js_1.default(0)
169
+ : decimal_js_1.default.max(0, new decimal_js_1.default(borrowedAfter)).div(borrowedBefore);
170
+ return {
171
+ debtBase: new decimal_js_1.default(debtBase).mul(fractionRemaining).toString(),
172
+ debtInterest: new decimal_js_1.default(debtInterest).mul(fractionRemaining).toString(),
173
+ };
174
+ };
175
+ exports.scaleMorphoMidnightDebtSplit = scaleMorphoMidnightDebtSplit;
143
176
  /**
144
177
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
145
178
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -169,12 +169,14 @@ function _getMorphoMidnightAccountData(provider, network, account, selectedMarke
169
169
  if (new decimal_js_1.default(positionInfo.debt.toString()).gt(0)) {
170
170
  try {
171
171
  const borrowInfo = yield (0, morphoMidnightHelpers_1.getMorphoMidnightUserBorrowInfo)(account, marketId, marketInfo.loanToken);
172
- borrowRate = borrowInfo.borrowRate;
173
- debtBase = borrowInfo.debtBase;
174
- debtInterest = borrowInfo.debtInterest;
175
- usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
176
- // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
177
- assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
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
+ }
178
180
  }
179
181
  catch (err) {
180
182
  // Orderbook API unavailable — keep the on-chain-only fallback above.
@@ -74,6 +74,24 @@ export declare const midnightSlippageParam: (slippagePercent: Dec.Value) => stri
74
74
  * The caller swallows errors — a missing rate must never block position rendering.
75
75
  */
76
76
  export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId: string, loanTokenSymbol: string) => Promise<MorphoMidnightBorrowInfo>;
77
+ /**
78
+ * The inverse of the split above: where `getMorphoMidnightUserBorrowInfo` reads a position's principal and
79
+ * interest off the indexer, this carries that same split forward through a payback, from a debt of
80
+ * `borrowedBefore` down to one of `borrowedAfter`. Retiring units retires principal and interest pro rata,
81
+ * so both scale by the same fraction.
82
+ *
83
+ * Deriving the interest as `borrowedAfter − debtBase` instead reads it off two different sources —
84
+ * `borrowed` is the chain's debt, `debtBase` the indexer's principal — so the entire gap between them lands
85
+ * in the interest whenever they disagree, which they do until the indexer catches up with a fresh borrow or
86
+ * payback: behind a borrow it inflates the interest by the debt the indexer has not seen yet, behind a
87
+ * payback it goes negative on a position that still owes. Callers detect that window as
88
+ * `debtBase + debtInterest !== debt`.
89
+ *
90
+ * Pro rata is also what keeps the answer sane when a payback retires debt at a different rate than the one
91
+ * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
92
+ * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
93
+ */
94
+ export declare const scaleMorphoMidnightDebtSplit: <T extends Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">>({ debtBase, debtInterest }: T, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
77
95
  /**
78
96
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
79
97
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -37,6 +37,12 @@ export const getMorphoMidnightAggregatedPositionData = ({ usedAssets, assetsData
37
37
  // borrowLimit = Σ collateralUsd_i * lltv_i (per-collateral lltv carried on assetsData)
38
38
  payload.borrowLimitUsd = getAssetsTotal(usedAssets, ({ isSupplied, collateral }) => isSupplied && collateral, ({ symbol, suppliedUsd }) => { var _a; return new Dec(suppliedUsd).mul(((_a = assetsData[symbol]) === null || _a === void 0 ? void 0 : _a.lltv) || 0); });
39
39
  payload.liquidationLimitUsd = payload.borrowLimitUsd;
40
+ // Same subtraction every other money market uses, but it does NOT mean the same thing here. Elsewhere
41
+ // `borrowedUsd` is debt at present value, so the remainder is what a borrow would pay out. Midnight
42
+ // records debt at its face value at maturity, so this is face-value headroom: borrowing it would add
43
+ // more debt than the number says, by the market's discount. Anything surfacing this as "what you can
44
+ // borrow" has to scale it by the loan-per-unit price first (`midnightPriceFromApy` off a book rate) —
45
+ // a correction that grows with the term, past 7% on a one-year market.
40
46
  const leftToBorrowUsd = new Dec(payload.borrowLimitUsd).sub(payload.borrowedUsd);
41
47
  payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
42
48
  const loanTokenPrice = ((_a = assetsData[marketInfo.loanToken]) === null || _a === void 0 ? void 0 : _a.price) || '0';
@@ -120,6 +126,32 @@ export const getMorphoMidnightUserBorrowInfo = (account, marketId, loanTokenSymb
120
126
  borrowRate, debtBase, debtInterest, debtTotal,
121
127
  };
122
128
  });
129
+ /**
130
+ * The inverse of the split above: where `getMorphoMidnightUserBorrowInfo` reads a position's principal and
131
+ * interest off the indexer, this carries that same split forward through a payback, from a debt of
132
+ * `borrowedBefore` down to one of `borrowedAfter`. Retiring units retires principal and interest pro rata,
133
+ * so both scale by the same fraction.
134
+ *
135
+ * Deriving the interest as `borrowedAfter − debtBase` instead reads it off two different sources —
136
+ * `borrowed` is the chain's debt, `debtBase` the indexer's principal — so the entire gap between them lands
137
+ * in the interest whenever they disagree, which they do until the indexer catches up with a fresh borrow or
138
+ * payback: behind a borrow it inflates the interest by the debt the indexer has not seen yet, behind a
139
+ * payback it goes negative on a position that still owes. Callers detect that window as
140
+ * `debtBase + debtInterest !== debt`.
141
+ *
142
+ * Pro rata is also what keeps the answer sane when a payback retires debt at a different rate than the one
143
+ * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
144
+ * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
145
+ */
146
+ export const scaleMorphoMidnightDebtSplit = ({ debtBase, debtInterest }, borrowedBefore, borrowedAfter) => {
147
+ const fractionRemaining = new Dec(borrowedBefore).lte(0)
148
+ ? new Dec(0)
149
+ : Dec.max(0, new Dec(borrowedAfter)).div(borrowedBefore);
150
+ return {
151
+ debtBase: new Dec(debtBase).mul(fractionRemaining).toString(),
152
+ debtInterest: new Dec(debtInterest).mul(fractionRemaining).toString(),
153
+ };
154
+ };
123
155
  /**
124
156
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
125
157
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -158,12 +158,14 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
158
158
  if (new Dec(positionInfo.debt.toString()).gt(0)) {
159
159
  try {
160
160
  const borrowInfo = yield getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
161
- borrowRate = borrowInfo.borrowRate;
162
- debtBase = borrowInfo.debtBase;
163
- debtInterest = borrowInfo.debtInterest;
164
- usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
165
- // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
166
- assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
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
+ }
167
169
  }
168
170
  catch (err) {
169
171
  // Orderbook API unavailable — keep the on-chain-only fallback above.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "2.1.127-midnight-10-dev",
3
+ "version": "2.1.127-midnight-12-dev",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -74,6 +74,12 @@ export const getMorphoMidnightAggregatedPositionData = ({
74
74
  );
75
75
  payload.liquidationLimitUsd = payload.borrowLimitUsd;
76
76
 
77
+ // Same subtraction every other money market uses, but it does NOT mean the same thing here. Elsewhere
78
+ // `borrowedUsd` is debt at present value, so the remainder is what a borrow would pay out. Midnight
79
+ // records debt at its face value at maturity, so this is face-value headroom: borrowing it would add
80
+ // more debt than the number says, by the market's discount. Anything surfacing this as "what you can
81
+ // borrow" has to scale it by the loan-per-unit price first (`midnightPriceFromApy` off a book rate) —
82
+ // a correction that grows with the term, past 7% on a one-year market.
77
83
  const leftToBorrowUsd = new Dec(payload.borrowLimitUsd).sub(payload.borrowedUsd);
78
84
  payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
79
85
 
@@ -250,6 +256,38 @@ export const getMorphoMidnightUserBorrowInfo = async (
250
256
  };
251
257
  };
252
258
 
259
+ /**
260
+ * The inverse of the split above: where `getMorphoMidnightUserBorrowInfo` reads a position's principal and
261
+ * interest off the indexer, this carries that same split forward through a payback, from a debt of
262
+ * `borrowedBefore` down to one of `borrowedAfter`. Retiring units retires principal and interest pro rata,
263
+ * so both scale by the same fraction.
264
+ *
265
+ * Deriving the interest as `borrowedAfter − debtBase` instead reads it off two different sources —
266
+ * `borrowed` is the chain's debt, `debtBase` the indexer's principal — so the entire gap between them lands
267
+ * in the interest whenever they disagree, which they do until the indexer catches up with a fresh borrow or
268
+ * payback: behind a borrow it inflates the interest by the debt the indexer has not seen yet, behind a
269
+ * payback it goes negative on a position that still owes. Callers detect that window as
270
+ * `debtBase + debtInterest !== debt`.
271
+ *
272
+ * Pro rata is also what keeps the answer sane when a payback retires debt at a different rate than the one
273
+ * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
274
+ * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
275
+ */
276
+ export const scaleMorphoMidnightDebtSplit = <T extends Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'>>(
277
+ { debtBase, debtInterest }: T,
278
+ borrowedBefore: Dec.Value,
279
+ borrowedAfter: Dec.Value,
280
+ ): Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'> => {
281
+ const fractionRemaining = new Dec(borrowedBefore).lte(0)
282
+ ? new Dec(0)
283
+ : Dec.max(0, new Dec(borrowedAfter)).div(borrowedBefore);
284
+
285
+ return {
286
+ debtBase: new Dec(debtBase).mul(fractionRemaining).toString(),
287
+ debtInterest: new Dec(debtInterest).mul(fractionRemaining).toString(),
288
+ };
289
+ };
290
+
253
291
  /**
254
292
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
255
293
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -167,15 +167,17 @@ export async function _getMorphoMidnightAccountData(provider: Client, network: N
167
167
  if (new Dec(positionInfo.debt.toString()).gt(0)) {
168
168
  try {
169
169
  const borrowInfo = await getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
170
- borrowRate = borrowInfo.borrowRate;
171
- debtBase = borrowInfo.debtBase;
172
- debtInterest = borrowInfo.debtInterest;
173
- usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
174
- // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
175
- assetsDataForApy = {
176
- ...marketInfo.assetsData,
177
- [marketInfo.loanToken]: { ...loanTokenData, borrowRate },
178
- };
170
+ if (new Dec(borrowInfo.debtTotal).gt(0)) {
171
+ borrowRate = borrowInfo.borrowRate;
172
+ debtBase = borrowInfo.debtBase;
173
+ debtInterest = borrowInfo.debtInterest;
174
+ usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
175
+ // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
176
+ assetsDataForApy = {
177
+ ...marketInfo.assetsData,
178
+ [marketInfo.loanToken]: { ...loanTokenData, borrowRate },
179
+ };
180
+ }
179
181
  } catch (err) {
180
182
  // Orderbook API unavailable — keep the on-chain-only fallback above.
181
183
  }