@defisaver/positions-sdk 2.1.127-midnight-12-dev → 2.1.127-midnight-14-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.
@@ -91,7 +91,7 @@ export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId
91
91
  * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
92
92
  * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
93
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">;
94
+ export declare const scaleMorphoMidnightDebtSplit: ({ debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
95
95
  /**
96
96
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
97
97
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -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,9 +166,12 @@ 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
172
  try {
173
+ // Curator-agnostic: `/users/:account/positions` is indexed off the Midnight singleton, so it carries
174
+ // Tenor-curated markets too. Only the *book* differs by curator, and that is quoted elsewhere.
171
175
  const borrowInfo = yield (0, morphoMidnightHelpers_1.getMorphoMidnightUserBorrowInfo)(account, marketId, marketInfo.loanToken);
172
176
  if (new decimal_js_1.default(borrowInfo.debtTotal).gt(0)) {
173
177
  borrowRate = borrowInfo.borrowRate;
@@ -176,10 +180,20 @@ function _getMorphoMidnightAccountData(provider, network, account, selectedMarke
176
180
  usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
177
181
  // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
178
182
  assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
183
+ const describesChainDebt = new decimal_js_1.default(borrowInfo.debtTotal).eq(debt);
184
+ const ratePriced = new decimal_js_1.default(borrowRate).gt(0) || new decimal_js_1.default(debtInterest).lte(0);
185
+ borrowInfoStatus = describesChainDebt && ratePriced
186
+ ? types_1.MorphoMidnightBorrowInfoStatus.Available
187
+ : types_1.MorphoMidnightBorrowInfoStatus.Pending;
188
+ }
189
+ else {
190
+ // No entry for the position: the API does not know it yet, rather than it having no principal.
191
+ borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Pending;
179
192
  }
180
193
  }
181
194
  catch (err) {
182
- // Orderbook API unavailablekeep the on-chain-only fallback above.
195
+ // Positions API unreachablethe fallback above still renders, and the next call may succeed.
196
+ borrowInfoStatus = types_1.MorphoMidnightBorrowInfoStatus.Pending;
183
197
  }
184
198
  }
185
199
  return Object.assign({ usedAssets,
@@ -187,7 +201,8 @@ function _getMorphoMidnightAccountData(provider, network, account, selectedMarke
187
201
  debt,
188
202
  borrowRate,
189
203
  debtBase,
190
- debtInterest, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, (0, morphoMidnightHelpers_1.getMorphoMidnightAggregatedPositionData)({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
204
+ debtInterest,
205
+ borrowInfoStatus, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, (0, morphoMidnightHelpers_1.getMorphoMidnightAggregatedPositionData)({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
191
206
  });
192
207
  }
193
208
  function getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
@@ -113,6 +113,21 @@ 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
+ */
127
+ export declare enum MorphoMidnightBorrowInfoStatus {
128
+ Available = "available",
129
+ Pending = "pending"
130
+ }
116
131
  export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
117
132
  usedAssets: MMUsedAssets;
118
133
  credit: string;
@@ -120,6 +135,7 @@ export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPosi
120
135
  borrowRate: string;
121
136
  debtBase: string;
122
137
  debtInterest: string;
138
+ borrowInfoStatus: MorphoMidnightBorrowInfoStatus;
123
139
  maturity: number;
124
140
  isMatured: boolean;
125
141
  }
@@ -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,19 @@ 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
+ */
43
+ var MorphoMidnightBorrowInfoStatus;
44
+ (function (MorphoMidnightBorrowInfoStatus) {
45
+ MorphoMidnightBorrowInfoStatus["Available"] = "available";
46
+ MorphoMidnightBorrowInfoStatus["Pending"] = "pending";
47
+ })(MorphoMidnightBorrowInfoStatus || (exports.MorphoMidnightBorrowInfoStatus = MorphoMidnightBorrowInfoStatus = {}));
@@ -91,7 +91,7 @@ export declare const getMorphoMidnightUserBorrowInfo: (account: string, marketId
91
91
  * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
92
92
  * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
93
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">;
94
+ export declare const scaleMorphoMidnightDebtSplit: ({ debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">, borrowedBefore: Dec.Value, borrowedAfter: Dec.Value) => Pick<MorphoMidnightBorrowInfo, "debtBase" | "debtInterest">;
95
95
  /**
96
96
  * One side of a market's resting order book, as rates rather than the API's WAD-scaled loan-per-unit
97
97
  * prices. Annualizing each price against time-to-maturity gives the rate a taker filling that offer gets
@@ -11,6 +11,7 @@ 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';
@@ -154,9 +155,12 @@ 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
161
  try {
162
+ // Curator-agnostic: `/users/:account/positions` is indexed off the Midnight singleton, so it carries
163
+ // Tenor-curated markets too. Only the *book* differs by curator, and that is quoted elsewhere.
160
164
  const borrowInfo = yield getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
161
165
  if (new Dec(borrowInfo.debtTotal).gt(0)) {
162
166
  borrowRate = borrowInfo.borrowRate;
@@ -165,10 +169,20 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
165
169
  usedAssets[marketInfo.loanToken].borrowRate = borrowRate;
166
170
  // Reflect the real borrow cost in netApy without mutating the shared marketInfo.assetsData.
167
171
  assetsDataForApy = Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.loanToken]: Object.assign(Object.assign({}, loanTokenData), { borrowRate }) });
172
+ const describesChainDebt = new Dec(borrowInfo.debtTotal).eq(debt);
173
+ const ratePriced = new Dec(borrowRate).gt(0) || new Dec(debtInterest).lte(0);
174
+ borrowInfoStatus = describesChainDebt && ratePriced
175
+ ? MorphoMidnightBorrowInfoStatus.Available
176
+ : MorphoMidnightBorrowInfoStatus.Pending;
177
+ }
178
+ else {
179
+ // No entry for the position: the API does not know it yet, rather than it having no principal.
180
+ borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
168
181
  }
169
182
  }
170
183
  catch (err) {
171
- // Orderbook API unavailablekeep the on-chain-only fallback above.
184
+ // Positions API unreachablethe fallback above still renders, and the next call may succeed.
185
+ borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
172
186
  }
173
187
  }
174
188
  return Object.assign({ usedAssets,
@@ -176,7 +190,8 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
176
190
  debt,
177
191
  borrowRate,
178
192
  debtBase,
179
- debtInterest, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
193
+ debtInterest,
194
+ borrowInfoStatus, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
180
195
  });
181
196
  }
182
197
  export function getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
@@ -113,6 +113,21 @@ 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
+ */
127
+ export declare enum MorphoMidnightBorrowInfoStatus {
128
+ Available = "available",
129
+ Pending = "pending"
130
+ }
116
131
  export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
117
132
  usedAssets: MMUsedAssets;
118
133
  credit: string;
@@ -120,6 +135,7 @@ export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPosi
120
135
  borrowRate: string;
121
136
  debtBase: string;
122
137
  debtInterest: string;
138
+ borrowInfoStatus: MorphoMidnightBorrowInfoStatus;
123
139
  maturity: number;
124
140
  isMatured: boolean;
125
141
  }
@@ -26,3 +26,19 @@ 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
+ */
40
+ export var MorphoMidnightBorrowInfoStatus;
41
+ (function (MorphoMidnightBorrowInfoStatus) {
42
+ MorphoMidnightBorrowInfoStatus["Available"] = "available";
43
+ MorphoMidnightBorrowInfoStatus["Pending"] = "pending";
44
+ })(MorphoMidnightBorrowInfoStatus || (MorphoMidnightBorrowInfoStatus = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "2.1.127-midnight-12-dev",
3
+ "version": "2.1.127-midnight-14-dev",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -273,8 +273,8 @@ export const getMorphoMidnightUserBorrowInfo = async (
273
273
  * it was opened at. Mirroring a borrow instead — principal growing by the assets received, interest by the
274
274
  * rest — hands back a negative interest as soon as the book sells units back cheaper than they were bought.
275
275
  */
276
- export const scaleMorphoMidnightDebtSplit = <T extends Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'>>(
277
- { debtBase, debtInterest }: T,
276
+ export const scaleMorphoMidnightDebtSplit = (
277
+ { debtBase, debtInterest }: Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'>,
278
278
  borrowedBefore: Dec.Value,
279
279
  borrowedAfter: Dec.Value,
280
280
  ): Pick<MorphoMidnightBorrowInfo, 'debtBase' | 'debtInterest'> => {
@@ -8,7 +8,7 @@ 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';
@@ -163,9 +163,12 @@ 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
  try {
170
+ // Curator-agnostic: `/users/:account/positions` is indexed off the Midnight singleton, so it carries
171
+ // Tenor-curated markets too. Only the *book* differs by curator, and that is quoted elsewhere.
169
172
  const borrowInfo = await getMorphoMidnightUserBorrowInfo(account, marketId, marketInfo.loanToken);
170
173
  if (new Dec(borrowInfo.debtTotal).gt(0)) {
171
174
  borrowRate = borrowInfo.borrowRate;
@@ -177,9 +180,18 @@ export async function _getMorphoMidnightAccountData(provider: Client, network: N
177
180
  ...marketInfo.assetsData,
178
181
  [marketInfo.loanToken]: { ...loanTokenData, borrowRate },
179
182
  };
183
+ const describesChainDebt = new Dec(borrowInfo.debtTotal).eq(debt);
184
+ const ratePriced = new Dec(borrowRate).gt(0) || new Dec(debtInterest).lte(0);
185
+ borrowInfoStatus = describesChainDebt && ratePriced
186
+ ? MorphoMidnightBorrowInfoStatus.Available
187
+ : MorphoMidnightBorrowInfoStatus.Pending;
188
+ } else {
189
+ // No entry for the position: the API does not know it yet, rather than it having no principal.
190
+ borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
180
191
  }
181
192
  } catch (err) {
182
- // Orderbook API unavailablekeep the on-chain-only fallback above.
193
+ // Positions API unreachablethe fallback above still renders, and the next call may succeed.
194
+ borrowInfoStatus = MorphoMidnightBorrowInfoStatus.Pending;
183
195
  }
184
196
  }
185
197
 
@@ -190,6 +202,7 @@ export async function _getMorphoMidnightAccountData(provider: Client, network: N
190
202
  borrowRate,
191
203
  debtBase,
192
204
  debtInterest,
205
+ borrowInfoStatus,
193
206
  maturity: marketInfo.maturity,
194
207
  isMatured: marketInfo.isMatured,
195
208
  ...getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }),
@@ -132,18 +132,32 @@ 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
+ */
146
+ export enum MorphoMidnightBorrowInfoStatus {
147
+ Available = 'available',
148
+ Pending = 'pending',
149
+ }
150
+
135
151
  // Fixed-rate/YTM (derived from entry price + orderbook) is intentionally absent in MVP:
136
152
  // MidnightView exposes no per-position rate, so a variable-MM-style APY would be misleading.
137
153
  export interface MorphoMidnightPositionData extends MorphoMidnightAggregatedPositionData {
138
154
  usedAssets: MMUsedAssets,
139
155
  credit: string, // lender credit units, face value at maturity (with interest); 0 for borrowers
140
156
  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
157
  borrowRate: string, // weighted-average borrow APY as a percent
145
158
  debtBase: string, // base borrowed (principal), loan-token units
146
159
  debtInterest: string, // debt − debtBase (fixed interest owed at maturity), loan-token units
160
+ borrowInfoStatus: MorphoMidnightBorrowInfoStatus,
147
161
  maturity: number,
148
162
  isMatured: boolean,
149
163
  }