@defisaver/positions-sdk 2.1.105 → 2.1.106

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.
@@ -86,6 +86,9 @@ const fetchHubData = (viewContract, hubAddress) => __awaiter(void 0, void 0, voi
86
86
  const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, network) => __awaiter(void 0, void 0, void 0, function* () {
87
87
  var _a, _b, _c, _d, _e, _f;
88
88
  const assetInfo = (0, tokens_1.getAssetInfoByAddress)(reserveAsset.underlying, network);
89
+ // `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
90
+ // tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
91
+ const isUnsupported = assetInfo.symbol === '?';
89
92
  const symbol = (0, utils_1.wethToEth)(assetInfo.symbol);
90
93
  const hubInfo = (0, aaveV4_1.getAaveV4HubByAddress)(network, reserveAsset.hub);
91
94
  if (!hubInfo) {
@@ -132,10 +135,23 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
132
135
  const premiumMultiplier = totalDrawnShares.isZero() ? new decimal_js_1.default(1) : totalDrawnShares.add(totalPremiumShares).div(totalDrawnShares);
133
136
  const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new decimal_js_1.default(1).minus(liquidityFee));
134
137
  const utilization = hubUtilization.times(100).toString();
138
+ // For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
139
+ // symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
140
+ // still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
141
+ const toEth = (raw) => {
142
+ const rawStr = raw.toString();
143
+ if ((0, utils_1.isMaxUint)(rawStr))
144
+ return rawStr;
145
+ if (isUnsupported)
146
+ return new decimal_js_1.default(rawStr || 0).div(new decimal_js_1.default(10).pow(reserveAsset.decimals)).toString();
147
+ return (0, tokens_1.assetAmountInEth)(rawStr, symbol);
148
+ };
135
149
  const hubLiquidityRaw = hubAsset.liquidity;
136
- const hubLiquidity = (0, utils_1.isMaxUint)(hubLiquidityRaw.toString()) ? hubLiquidityRaw.toString() : (0, tokens_1.assetAmountInEth)(hubLiquidityRaw.toString(), symbol);
150
+ const hubLiquidity = toEth(hubLiquidityRaw.toString());
137
151
  return ({
138
152
  symbol,
153
+ decimals: reserveAsset.decimals,
154
+ isUnsupported,
139
155
  underlying: reserveAsset.underlying,
140
156
  hub: hubInfo.address,
141
157
  hubName: hubInfo === null || hubInfo === void 0 ? void 0 : hubInfo.label,
@@ -149,12 +165,12 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
149
165
  liquidationFee: new decimal_js_1.default(reserveAsset.liquidationFee).div(10000).toNumber(),
150
166
  maxLiquidationBonus: new decimal_js_1.default(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
151
167
  price: new decimal_js_1.default(reserveAsset.price).div(new decimal_js_1.default(10).pow(oracleDecimals)).toString(),
152
- totalSupplied: (0, utils_1.isMaxUint)(totalSuppliedRaw.toString()) ? totalSuppliedRaw.toString() : (0, tokens_1.assetAmountInEth)(totalSuppliedRaw.toString(), symbol),
153
- totalDrawn: (0, utils_1.isMaxUint)(totalDrawnRaw.toString()) ? totalDrawnRaw.toString() : (0, tokens_1.assetAmountInEth)(totalDrawnRaw.toString(), symbol),
154
- totalPremium: (0, utils_1.isMaxUint)(totalPremiumRaw.toString()) ? totalPremiumRaw.toString() : (0, tokens_1.assetAmountInEth)(totalPremiumRaw.toString(), symbol),
155
- totalDebt: (0, utils_1.isMaxUint)(totalDebtRaw.toString()) ? totalDebtRaw.toString() : (0, tokens_1.assetAmountInEth)(totalDebtRaw.toString(), symbol),
156
- supplyCap: (0, utils_1.isMaxUint)(supplyCapRaw.toString()) ? supplyCapRaw.toString() : (0, tokens_1.assetAmountInEth)(supplyCapRaw.toString(), symbol),
157
- borrowCap: (0, utils_1.isMaxUint)(borrowCapRaw.toString()) ? borrowCapRaw.toString() : (0, tokens_1.assetAmountInEth)(borrowCapRaw.toString(), symbol),
168
+ totalSupplied: toEth(totalSuppliedRaw.toString()),
169
+ totalDrawn: toEth(totalDrawnRaw.toString()),
170
+ totalPremium: toEth(totalPremiumRaw.toString()),
171
+ totalDebt: toEth(totalDebtRaw.toString()),
172
+ supplyCap: toEth(supplyCapRaw.toString()),
173
+ borrowCap: toEth(borrowCapRaw.toString()),
158
174
  spokeActive: reserveAsset.spokeActive,
159
175
  spokeHalted: reserveAsset.spokeHalted,
160
176
  drawnRate: drawnRate.toString(),
@@ -162,10 +178,10 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
162
178
  supplyRate: (0, moneymarket_1.aprToApy)(supplyApr.toString()),
163
179
  supplyIncentives,
164
180
  borrowIncentives,
165
- canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
166
- canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
167
- canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
168
- canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
181
+ canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
182
+ canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
183
+ canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
184
+ canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
169
185
  utilization,
170
186
  hubLiquidity,
171
187
  premiumMultiplier: premiumMultiplier.toString(),
@@ -208,17 +224,33 @@ function _getAaveV4AccountData(provider_1, network_1, spokeData_1, address_1) {
208
224
  const healthFactorFromContract = new decimal_js_1.default(loanData.healthFactor.toString());
209
225
  const healthFactor = (0, utils_1.isMaxUint)(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
210
226
  const usedAssets = loanData.reserves.reduce((acc, usedReserveAsset) => {
211
- const identifier = `${(0, utils_1.wethToEth)((0, tokens_1.getAssetInfoByAddress)(usedReserveAsset.underlying, network).symbol)}-${+usedReserveAsset.reserveId.toString()}`;
227
+ var _a, _b, _c, _d;
228
+ const assetInfo = (0, tokens_1.getAssetInfoByAddress)(usedReserveAsset.underlying, network);
229
+ const isUnsupported = assetInfo.symbol === '?';
230
+ const symbol = (0, utils_1.wethToEth)(assetInfo.symbol);
231
+ const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
212
232
  const reserveData = spokeData.assetsData[identifier];
213
- const price = reserveData.price;
214
- const supplied = (0, utils_1.isMaxUint)(usedReserveAsset.supplied.toString()) ? usedReserveAsset.supplied.toString() : (0, tokens_1.assetAmountInEth)(usedReserveAsset.supplied.toString(), reserveData.symbol);
215
- const drawn = (0, utils_1.isMaxUint)(usedReserveAsset.drawn.toString()) ? usedReserveAsset.drawn.toString() : (0, tokens_1.assetAmountInEth)(usedReserveAsset.drawn.toString(), reserveData.symbol);
216
- const premium = (0, utils_1.isMaxUint)(usedReserveAsset.premium.toString()) ? usedReserveAsset.premium.toString() : (0, tokens_1.assetAmountInEth)(usedReserveAsset.premium.toString(), reserveData.symbol);
217
- const borrowed = (0, utils_1.isMaxUint)(usedReserveAsset.totalDebt.toString()) ? usedReserveAsset.totalDebt.toString() : (0, tokens_1.assetAmountInEth)(usedReserveAsset.totalDebt.toString(), reserveData.symbol);
233
+ const price = (_a = reserveData === null || reserveData === void 0 ? void 0 : reserveData.price) !== null && _a !== void 0 ? _a : '0';
234
+ // For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
235
+ // from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
236
+ // back to '0' and keep the entry read-only.
237
+ const toEth = (raw) => {
238
+ if ((0, utils_1.isMaxUint)(raw))
239
+ return raw;
240
+ if (!reserveData)
241
+ return '0';
242
+ if (isUnsupported)
243
+ return new decimal_js_1.default(raw || 0).div(new decimal_js_1.default(10).pow(reserveData.decimals)).toString();
244
+ return (0, tokens_1.assetAmountInEth)(raw, reserveData.symbol);
245
+ };
246
+ const supplied = toEth(usedReserveAsset.supplied.toString());
247
+ const drawn = toEth(usedReserveAsset.drawn.toString());
248
+ const premium = toEth(usedReserveAsset.premium.toString());
249
+ const borrowed = toEth(usedReserveAsset.totalDebt.toString());
218
250
  acc[identifier] = {
219
- symbol: reserveData.symbol,
220
- hubName: reserveData.hubName,
221
- assetId: reserveData.assetId,
251
+ symbol: (_b = reserveData === null || reserveData === void 0 ? void 0 : reserveData.symbol) !== null && _b !== void 0 ? _b : symbol,
252
+ hubName: (_c = reserveData === null || reserveData === void 0 ? void 0 : reserveData.hubName) !== null && _c !== void 0 ? _c : '',
253
+ assetId: (_d = reserveData === null || reserveData === void 0 ? void 0 : reserveData.assetId) !== null && _d !== void 0 ? _d : 0,
222
254
  reserveId: +usedReserveAsset.reserveId.toString(),
223
255
  supplied,
224
256
  suppliedUsd: new decimal_js_1.default(supplied).mul(price).toString(),
@@ -232,6 +264,7 @@ function _getAaveV4AccountData(provider_1, network_1, spokeData_1, address_1) {
232
264
  isBorrowed: usedReserveAsset.isBorrowing,
233
265
  collateral: usedReserveAsset.isUsingAsCollateral,
234
266
  collateralFactor: new decimal_js_1.default(usedReserveAsset.collateralFactor).div(10000).toNumber(),
267
+ isUnsupported: isUnsupported || !reserveData,
235
268
  };
236
269
  return acc;
237
270
  }, {});
@@ -74,6 +74,8 @@ export interface AaveV4ReserveAssetOnChain {
74
74
  }
75
75
  export interface AaveV4ReserveAssetData {
76
76
  symbol: string;
77
+ /** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
78
+ decimals: number;
77
79
  underlying: EthAddress;
78
80
  hub: EthAddress;
79
81
  hubName: string;
@@ -119,6 +121,11 @@ export interface AaveV4ReserveAssetData {
119
121
  hubLiquidity: string;
120
122
  premiumMultiplier: string;
121
123
  liquidityFee: string;
124
+ /**
125
+ * True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
126
+ * The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
127
+ */
128
+ isUnsupported?: boolean;
122
129
  }
123
130
  export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
124
131
  export interface AaveV4UsedReserveAsset {
@@ -138,6 +145,8 @@ export interface AaveV4UsedReserveAsset {
138
145
  isBorrowed: boolean;
139
146
  collateral: boolean;
140
147
  collateralFactor: number;
148
+ /** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
149
+ isUnsupported?: boolean;
141
150
  }
142
151
  export interface AaveV4AggregatedPositionData {
143
152
  suppliedUsd: string;
@@ -41,6 +41,9 @@ const fetchHubData = (viewContract, hubAddress) => __awaiter(void 0, void 0, voi
41
41
  const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, network) => __awaiter(void 0, void 0, void 0, function* () {
42
42
  var _a, _b, _c, _d, _e, _f;
43
43
  const assetInfo = getAssetInfoByAddress(reserveAsset.underlying, network);
44
+ // `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
45
+ // tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
46
+ const isUnsupported = assetInfo.symbol === '?';
44
47
  const symbol = wethToEth(assetInfo.symbol);
45
48
  const hubInfo = getAaveV4HubByAddress(network, reserveAsset.hub);
46
49
  if (!hubInfo) {
@@ -87,10 +90,23 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
87
90
  const premiumMultiplier = totalDrawnShares.isZero() ? new Dec(1) : totalDrawnShares.add(totalPremiumShares).div(totalDrawnShares);
88
91
  const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new Dec(1).minus(liquidityFee));
89
92
  const utilization = hubUtilization.times(100).toString();
93
+ // For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
94
+ // symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
95
+ // still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
96
+ const toEth = (raw) => {
97
+ const rawStr = raw.toString();
98
+ if (isMaxUint(rawStr))
99
+ return rawStr;
100
+ if (isUnsupported)
101
+ return new Dec(rawStr || 0).div(new Dec(10).pow(reserveAsset.decimals)).toString();
102
+ return assetAmountInEth(rawStr, symbol);
103
+ };
90
104
  const hubLiquidityRaw = hubAsset.liquidity;
91
- const hubLiquidity = isMaxUint(hubLiquidityRaw.toString()) ? hubLiquidityRaw.toString() : assetAmountInEth(hubLiquidityRaw.toString(), symbol);
105
+ const hubLiquidity = toEth(hubLiquidityRaw.toString());
92
106
  return ({
93
107
  symbol,
108
+ decimals: reserveAsset.decimals,
109
+ isUnsupported,
94
110
  underlying: reserveAsset.underlying,
95
111
  hub: hubInfo.address,
96
112
  hubName: hubInfo === null || hubInfo === void 0 ? void 0 : hubInfo.label,
@@ -104,12 +120,12 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
104
120
  liquidationFee: new Dec(reserveAsset.liquidationFee).div(10000).toNumber(),
105
121
  maxLiquidationBonus: new Dec(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
106
122
  price: new Dec(reserveAsset.price).div(new Dec(10).pow(oracleDecimals)).toString(),
107
- totalSupplied: isMaxUint(totalSuppliedRaw.toString()) ? totalSuppliedRaw.toString() : assetAmountInEth(totalSuppliedRaw.toString(), symbol),
108
- totalDrawn: isMaxUint(totalDrawnRaw.toString()) ? totalDrawnRaw.toString() : assetAmountInEth(totalDrawnRaw.toString(), symbol),
109
- totalPremium: isMaxUint(totalPremiumRaw.toString()) ? totalPremiumRaw.toString() : assetAmountInEth(totalPremiumRaw.toString(), symbol),
110
- totalDebt: isMaxUint(totalDebtRaw.toString()) ? totalDebtRaw.toString() : assetAmountInEth(totalDebtRaw.toString(), symbol),
111
- supplyCap: isMaxUint(supplyCapRaw.toString()) ? supplyCapRaw.toString() : assetAmountInEth(supplyCapRaw.toString(), symbol),
112
- borrowCap: isMaxUint(borrowCapRaw.toString()) ? borrowCapRaw.toString() : assetAmountInEth(borrowCapRaw.toString(), symbol),
123
+ totalSupplied: toEth(totalSuppliedRaw.toString()),
124
+ totalDrawn: toEth(totalDrawnRaw.toString()),
125
+ totalPremium: toEth(totalPremiumRaw.toString()),
126
+ totalDebt: toEth(totalDebtRaw.toString()),
127
+ supplyCap: toEth(supplyCapRaw.toString()),
128
+ borrowCap: toEth(borrowCapRaw.toString()),
113
129
  spokeActive: reserveAsset.spokeActive,
114
130
  spokeHalted: reserveAsset.spokeHalted,
115
131
  drawnRate: drawnRate.toString(),
@@ -117,10 +133,10 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
117
133
  supplyRate: aprToApy(supplyApr.toString()),
118
134
  supplyIncentives,
119
135
  borrowIncentives,
120
- canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
121
- canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
122
- canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
123
- canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
136
+ canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
137
+ canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
138
+ canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
139
+ canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
124
140
  utilization,
125
141
  hubLiquidity,
126
142
  premiumMultiplier: premiumMultiplier.toString(),
@@ -163,17 +179,33 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
163
179
  const healthFactorFromContract = new Dec(loanData.healthFactor.toString());
164
180
  const healthFactor = isMaxUint(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
165
181
  const usedAssets = loanData.reserves.reduce((acc, usedReserveAsset) => {
166
- const identifier = `${wethToEth(getAssetInfoByAddress(usedReserveAsset.underlying, network).symbol)}-${+usedReserveAsset.reserveId.toString()}`;
182
+ var _a, _b, _c, _d;
183
+ const assetInfo = getAssetInfoByAddress(usedReserveAsset.underlying, network);
184
+ const isUnsupported = assetInfo.symbol === '?';
185
+ const symbol = wethToEth(assetInfo.symbol);
186
+ const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
167
187
  const reserveData = spokeData.assetsData[identifier];
168
- const price = reserveData.price;
169
- const supplied = isMaxUint(usedReserveAsset.supplied.toString()) ? usedReserveAsset.supplied.toString() : assetAmountInEth(usedReserveAsset.supplied.toString(), reserveData.symbol);
170
- const drawn = isMaxUint(usedReserveAsset.drawn.toString()) ? usedReserveAsset.drawn.toString() : assetAmountInEth(usedReserveAsset.drawn.toString(), reserveData.symbol);
171
- const premium = isMaxUint(usedReserveAsset.premium.toString()) ? usedReserveAsset.premium.toString() : assetAmountInEth(usedReserveAsset.premium.toString(), reserveData.symbol);
172
- const borrowed = isMaxUint(usedReserveAsset.totalDebt.toString()) ? usedReserveAsset.totalDebt.toString() : assetAmountInEth(usedReserveAsset.totalDebt.toString(), reserveData.symbol);
188
+ const price = (_a = reserveData === null || reserveData === void 0 ? void 0 : reserveData.price) !== null && _a !== void 0 ? _a : '0';
189
+ // For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
190
+ // from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
191
+ // back to '0' and keep the entry read-only.
192
+ const toEth = (raw) => {
193
+ if (isMaxUint(raw))
194
+ return raw;
195
+ if (!reserveData)
196
+ return '0';
197
+ if (isUnsupported)
198
+ return new Dec(raw || 0).div(new Dec(10).pow(reserveData.decimals)).toString();
199
+ return assetAmountInEth(raw, reserveData.symbol);
200
+ };
201
+ const supplied = toEth(usedReserveAsset.supplied.toString());
202
+ const drawn = toEth(usedReserveAsset.drawn.toString());
203
+ const premium = toEth(usedReserveAsset.premium.toString());
204
+ const borrowed = toEth(usedReserveAsset.totalDebt.toString());
173
205
  acc[identifier] = {
174
- symbol: reserveData.symbol,
175
- hubName: reserveData.hubName,
176
- assetId: reserveData.assetId,
206
+ symbol: (_b = reserveData === null || reserveData === void 0 ? void 0 : reserveData.symbol) !== null && _b !== void 0 ? _b : symbol,
207
+ hubName: (_c = reserveData === null || reserveData === void 0 ? void 0 : reserveData.hubName) !== null && _c !== void 0 ? _c : '',
208
+ assetId: (_d = reserveData === null || reserveData === void 0 ? void 0 : reserveData.assetId) !== null && _d !== void 0 ? _d : 0,
177
209
  reserveId: +usedReserveAsset.reserveId.toString(),
178
210
  supplied,
179
211
  suppliedUsd: new Dec(supplied).mul(price).toString(),
@@ -187,6 +219,7 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
187
219
  isBorrowed: usedReserveAsset.isBorrowing,
188
220
  collateral: usedReserveAsset.isUsingAsCollateral,
189
221
  collateralFactor: new Dec(usedReserveAsset.collateralFactor).div(10000).toNumber(),
222
+ isUnsupported: isUnsupported || !reserveData,
190
223
  };
191
224
  return acc;
192
225
  }, {});
@@ -74,6 +74,8 @@ export interface AaveV4ReserveAssetOnChain {
74
74
  }
75
75
  export interface AaveV4ReserveAssetData {
76
76
  symbol: string;
77
+ /** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
78
+ decimals: number;
77
79
  underlying: EthAddress;
78
80
  hub: EthAddress;
79
81
  hubName: string;
@@ -119,6 +121,11 @@ export interface AaveV4ReserveAssetData {
119
121
  hubLiquidity: string;
120
122
  premiumMultiplier: string;
121
123
  liquidityFee: string;
124
+ /**
125
+ * True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
126
+ * The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
127
+ */
128
+ isUnsupported?: boolean;
122
129
  }
123
130
  export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
124
131
  export interface AaveV4UsedReserveAsset {
@@ -138,6 +145,8 @@ export interface AaveV4UsedReserveAsset {
138
145
  isBorrowed: boolean;
139
146
  collateral: boolean;
140
147
  collateralFactor: number;
148
+ /** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
149
+ isUnsupported?: boolean;
141
150
  }
142
151
  export interface AaveV4AggregatedPositionData {
143
152
  suppliedUsd: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "2.1.105",
3
+ "version": "2.1.106",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -50,6 +50,9 @@ const fetchHubData = async (viewContract: ReturnType<typeof AaveV4ViewContractVi
50
50
 
51
51
  const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAsset: AaveV4HubAssetOnChainData, reserveId: number, oracleDecimals: number, network: NetworkNumber): Promise<AaveV4ReserveAssetData> => {
52
52
  const assetInfo = getAssetInfoByAddress(reserveAsset.underlying, network);
53
+ // `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
54
+ // tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
55
+ const isUnsupported = assetInfo.symbol === '?';
53
56
  const symbol = wethToEth(assetInfo.symbol);
54
57
  const hubInfo = getAaveV4HubByAddress(network, reserveAsset.hub);
55
58
  if (!hubInfo) {
@@ -101,11 +104,23 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
101
104
  const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new Dec(1).minus(liquidityFee));
102
105
  const utilization = hubUtilization.times(100).toString();
103
106
 
107
+ // For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
108
+ // symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
109
+ // still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
110
+ const toEth = (raw: string | number | bigint) => {
111
+ const rawStr = raw.toString();
112
+ if (isMaxUint(rawStr)) return rawStr;
113
+ if (isUnsupported) return new Dec(rawStr || 0).div(new Dec(10).pow(reserveAsset.decimals)).toString();
114
+ return assetAmountInEth(rawStr, symbol);
115
+ };
116
+
104
117
  const hubLiquidityRaw = hubAsset.liquidity;
105
- const hubLiquidity = isMaxUint(hubLiquidityRaw.toString()) ? hubLiquidityRaw.toString() : assetAmountInEth(hubLiquidityRaw.toString(), symbol);
118
+ const hubLiquidity = toEth(hubLiquidityRaw.toString());
106
119
 
107
120
  return ({
108
121
  symbol,
122
+ decimals: reserveAsset.decimals,
123
+ isUnsupported,
109
124
  underlying: reserveAsset.underlying,
110
125
  hub: hubInfo.address,
111
126
  hubName: hubInfo?.label,
@@ -119,12 +134,12 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
119
134
  liquidationFee: new Dec(reserveAsset.liquidationFee).div(10000).toNumber(),
120
135
  maxLiquidationBonus: new Dec(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
121
136
  price: new Dec(reserveAsset.price).div(new Dec(10).pow(oracleDecimals)).toString(),
122
- totalSupplied: isMaxUint(totalSuppliedRaw.toString()) ? totalSuppliedRaw.toString() : assetAmountInEth(totalSuppliedRaw.toString(), symbol),
123
- totalDrawn: isMaxUint(totalDrawnRaw.toString()) ? totalDrawnRaw.toString() : assetAmountInEth(totalDrawnRaw.toString(), symbol),
124
- totalPremium: isMaxUint(totalPremiumRaw.toString()) ? totalPremiumRaw.toString() : assetAmountInEth(totalPremiumRaw.toString(), symbol),
125
- totalDebt: isMaxUint(totalDebtRaw.toString()) ? totalDebtRaw.toString() : assetAmountInEth(totalDebtRaw.toString(), symbol),
126
- supplyCap: isMaxUint(supplyCapRaw.toString()) ? supplyCapRaw.toString() : assetAmountInEth(supplyCapRaw.toString(), symbol),
127
- borrowCap: isMaxUint(borrowCapRaw.toString()) ? borrowCapRaw.toString() : assetAmountInEth(borrowCapRaw.toString(), symbol),
137
+ totalSupplied: toEth(totalSuppliedRaw.toString()),
138
+ totalDrawn: toEth(totalDrawnRaw.toString()),
139
+ totalPremium: toEth(totalPremiumRaw.toString()),
140
+ totalDebt: toEth(totalDebtRaw.toString()),
141
+ supplyCap: toEth(supplyCapRaw.toString()),
142
+ borrowCap: toEth(borrowCapRaw.toString()),
128
143
  spokeActive: reserveAsset.spokeActive,
129
144
  spokeHalted: reserveAsset.spokeHalted,
130
145
  drawnRate: drawnRate.toString(),
@@ -132,10 +147,10 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
132
147
  supplyRate: aprToApy(supplyApr.toString()),
133
148
  supplyIncentives,
134
149
  borrowIncentives,
135
- canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
136
- canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
137
- canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
138
- canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
150
+ canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
151
+ canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
152
+ canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
153
+ canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
139
154
  utilization,
140
155
  hubLiquidity,
141
156
  premiumMultiplier: premiumMultiplier.toString(),
@@ -182,17 +197,29 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
182
197
  const healthFactorFromContract = new Dec(loanData.healthFactor.toString());
183
198
  const healthFactor = isMaxUint(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
184
199
  const usedAssets = loanData.reserves.reduce((acc: AaveV4UsedReserveAssets, usedReserveAsset) => {
185
- const identifier = `${wethToEth(getAssetInfoByAddress(usedReserveAsset.underlying, network).symbol)}-${+usedReserveAsset.reserveId.toString()}`;
200
+ const assetInfo = getAssetInfoByAddress(usedReserveAsset.underlying, network);
201
+ const isUnsupported = assetInfo.symbol === '?';
202
+ const symbol = wethToEth(assetInfo.symbol);
203
+ const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
186
204
  const reserveData = spokeData.assetsData[identifier];
187
- const price = reserveData.price;
188
- const supplied = isMaxUint(usedReserveAsset.supplied.toString()) ? usedReserveAsset.supplied.toString() : assetAmountInEth(usedReserveAsset.supplied.toString(), reserveData.symbol);
189
- const drawn = isMaxUint(usedReserveAsset.drawn.toString()) ? usedReserveAsset.drawn.toString() : assetAmountInEth(usedReserveAsset.drawn.toString(), reserveData.symbol);
190
- const premium = isMaxUint(usedReserveAsset.premium.toString()) ? usedReserveAsset.premium.toString() : assetAmountInEth(usedReserveAsset.premium.toString(), reserveData.symbol);
191
- const borrowed = isMaxUint(usedReserveAsset.totalDebt.toString()) ? usedReserveAsset.totalDebt.toString() : assetAmountInEth(usedReserveAsset.totalDebt.toString(), reserveData.symbol);
205
+ const price = reserveData?.price ?? '0';
206
+ // For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
207
+ // from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
208
+ // back to '0' and keep the entry read-only.
209
+ const toEth = (raw: string) => {
210
+ if (isMaxUint(raw)) return raw;
211
+ if (!reserveData) return '0';
212
+ if (isUnsupported) return new Dec(raw || 0).div(new Dec(10).pow(reserveData.decimals)).toString();
213
+ return assetAmountInEth(raw, reserveData.symbol);
214
+ };
215
+ const supplied = toEth(usedReserveAsset.supplied.toString());
216
+ const drawn = toEth(usedReserveAsset.drawn.toString());
217
+ const premium = toEth(usedReserveAsset.premium.toString());
218
+ const borrowed = toEth(usedReserveAsset.totalDebt.toString());
192
219
  acc[identifier] = {
193
- symbol: reserveData.symbol,
194
- hubName: reserveData.hubName,
195
- assetId: reserveData.assetId,
220
+ symbol: reserveData?.symbol ?? symbol,
221
+ hubName: reserveData?.hubName ?? '',
222
+ assetId: reserveData?.assetId ?? 0,
196
223
  reserveId: +usedReserveAsset.reserveId.toString(),
197
224
  supplied,
198
225
  suppliedUsd: new Dec(supplied).mul(price).toString(),
@@ -206,6 +233,7 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
206
233
  isBorrowed: usedReserveAsset.isBorrowing,
207
234
  collateral: usedReserveAsset.isUsingAsCollateral,
208
235
  collateralFactor: new Dec(usedReserveAsset.collateralFactor).div(10000).toNumber(),
236
+ isUnsupported: isUnsupported || !reserveData,
209
237
  };
210
238
  return acc;
211
239
  }, {});
@@ -85,6 +85,8 @@ export interface AaveV4ReserveAssetOnChain {
85
85
 
86
86
  export interface AaveV4ReserveAssetData {
87
87
  symbol: string,
88
+ /** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
89
+ decimals: number,
88
90
  underlying: EthAddress,
89
91
  hub: EthAddress,
90
92
  hubName: string,
@@ -130,6 +132,11 @@ export interface AaveV4ReserveAssetData {
130
132
  hubLiquidity: string,
131
133
  premiumMultiplier: string;
132
134
  liquidityFee: string;
135
+ /**
136
+ * True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
137
+ * The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
138
+ */
139
+ isUnsupported?: boolean;
133
140
  }
134
141
 
135
142
  export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
@@ -151,6 +158,8 @@ export interface AaveV4UsedReserveAsset {
151
158
  isBorrowed: boolean,
152
159
  collateral: boolean,
153
160
  collateralFactor: number,
161
+ /** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
162
+ isUnsupported?: boolean,
154
163
  }
155
164
 
156
165
  export interface AaveV4AggregatedPositionData {