@defisaver/positions-sdk 2.1.167 → 2.1.168

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.
Files changed (78) hide show
  1. package/cjs/aaveV2/index.js +8 -29
  2. package/cjs/aaveV3/index.js +2 -31
  3. package/cjs/aaveV4/index.d.ts +25 -0
  4. package/cjs/aaveV4/index.js +4 -1
  5. package/cjs/compoundV2/index.d.ts +1 -1
  6. package/cjs/compoundV2/index.js +2 -2
  7. package/cjs/curveUsd/index.d.ts +1 -1
  8. package/cjs/curveUsd/index.js +6 -1
  9. package/cjs/fluid/index.js +13 -12
  10. package/cjs/helpers/aaveBalances.d.ts +5 -0
  11. package/cjs/helpers/aaveBalances.js +51 -0
  12. package/cjs/helpers/fluidBalances.d.ts +6 -0
  13. package/cjs/helpers/fluidBalances.js +36 -0
  14. package/cjs/liquityV2/index.d.ts +8 -0
  15. package/cjs/liquityV2/index.js +3 -3
  16. package/cjs/llamaLend/index.d.ts +1 -1
  17. package/cjs/llamaLend/index.js +6 -1
  18. package/cjs/morphoMidnight/index.d.ts +1 -1
  19. package/cjs/morphoMidnight/index.js +6 -1
  20. package/cjs/portfolio/index.d.ts +1 -0
  21. package/cjs/portfolio/index.js +3 -0
  22. package/cjs/portfolio/lendingSummaries.d.ts +7 -0
  23. package/cjs/portfolio/lendingSummaries.js +262 -0
  24. package/cjs/portfolio/lendingSummaryTransport.d.ts +8 -0
  25. package/cjs/portfolio/lendingSummaryTransport.js +109 -0
  26. package/cjs/spark/index.js +2 -31
  27. package/cjs/types/index.d.ts +1 -0
  28. package/cjs/types/index.js +1 -0
  29. package/cjs/types/lendingSummary.d.ts +34 -0
  30. package/cjs/types/lendingSummary.js +2 -0
  31. package/esm/aaveV2/index.js +11 -32
  32. package/esm/aaveV3/index.js +3 -32
  33. package/esm/aaveV4/index.d.ts +25 -0
  34. package/esm/aaveV4/index.js +3 -1
  35. package/esm/compoundV2/index.d.ts +1 -1
  36. package/esm/compoundV2/index.js +2 -2
  37. package/esm/curveUsd/index.d.ts +1 -1
  38. package/esm/curveUsd/index.js +6 -1
  39. package/esm/fluid/index.js +13 -12
  40. package/esm/helpers/aaveBalances.d.ts +5 -0
  41. package/esm/helpers/aaveBalances.js +45 -0
  42. package/esm/helpers/fluidBalances.d.ts +6 -0
  43. package/esm/helpers/fluidBalances.js +28 -0
  44. package/esm/liquityV2/index.d.ts +8 -0
  45. package/esm/liquityV2/index.js +1 -1
  46. package/esm/llamaLend/index.d.ts +1 -1
  47. package/esm/llamaLend/index.js +6 -1
  48. package/esm/morphoMidnight/index.d.ts +1 -1
  49. package/esm/morphoMidnight/index.js +6 -1
  50. package/esm/portfolio/index.d.ts +1 -0
  51. package/esm/portfolio/index.js +1 -0
  52. package/esm/portfolio/lendingSummaries.d.ts +7 -0
  53. package/esm/portfolio/lendingSummaries.js +256 -0
  54. package/esm/portfolio/lendingSummaryTransport.d.ts +8 -0
  55. package/esm/portfolio/lendingSummaryTransport.js +104 -0
  56. package/esm/spark/index.js +4 -33
  57. package/esm/types/index.d.ts +1 -0
  58. package/esm/types/index.js +1 -0
  59. package/esm/types/lendingSummary.d.ts +34 -0
  60. package/esm/types/lendingSummary.js +1 -0
  61. package/package.json +1 -1
  62. package/src/aaveV2/index.ts +8 -48
  63. package/src/aaveV3/index.ts +2 -48
  64. package/src/aaveV4/index.ts +6 -1
  65. package/src/compoundV2/index.ts +2 -2
  66. package/src/curveUsd/index.ts +6 -1
  67. package/src/fluid/index.ts +13 -12
  68. package/src/helpers/aaveBalances.ts +41 -0
  69. package/src/helpers/fluidBalances.ts +34 -0
  70. package/src/liquityV2/index.ts +1 -1
  71. package/src/llamaLend/index.ts +6 -1
  72. package/src/morphoMidnight/index.ts +6 -1
  73. package/src/portfolio/index.ts +2 -0
  74. package/src/portfolio/lendingSummaries.ts +216 -0
  75. package/src/portfolio/lendingSummaryTransport.ts +84 -0
  76. package/src/spark/index.ts +3 -49
  77. package/src/types/index.ts +2 -1
  78. package/src/types/lendingSummary.ts +41 -0
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import Dec from 'decimal.js';
11
11
  import { assetAmountInEth, assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
12
- import { getViemProvider } from '../services/viem';
12
+ import { getViemProvider, setViemBlockNumber } from '../services/viem';
13
13
  import { IncentiveKind, } from '../types';
14
14
  import { AaveV4ViewContractViem } from '../contracts';
15
15
  import { getStakingApy, STAKING_ASSETS } from '../staking';
@@ -251,6 +251,8 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
251
251
  riskPremiumBps });
252
252
  });
253
253
  }
254
+ /** Shared raw read; no spoke metadata or market enrichment. */
255
+ export const _getAaveV4LoanBalances = (provider, network, block, address, spoke) => (AaveV4ViewContractViem(provider, network, block).read.getLoanData([spoke, address], setViemBlockNumber(block)));
254
256
  /**
255
257
  * Lightweight existence check for Loan Shifter / UI discovery.
256
258
  * Reads only `getLoanData(spoke, user)` and returns whether any reserve has
@@ -17,7 +17,7 @@ export declare const EMPTY_COMPOUND_DATA: {
17
17
  borrowStableSupplyUnstable: boolean;
18
18
  exposure: string;
19
19
  };
20
- export declare const _getCompoundV2AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
20
+ export declare const _getCompoundV2AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, tokens?: EthAddress[]) => Promise<PositionBalances>;
21
21
  export declare const getCompoundV2AccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
22
22
  export declare const _getCompoundV2AccountData: (provider: Client, network: NetworkNumber, address: EthAddress, assetsData: CompoundV2AssetsData) => Promise<CompoundV2PositionData>;
23
23
  export declare const getCompoundV2AccountData: (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, assetsData: CompoundV2AssetsData) => Promise<CompoundV2PositionData>;
@@ -101,7 +101,7 @@ const getAllMarketAddresses = (provider, network, block) => __awaiter(void 0, vo
101
101
  const contract = ComptrollerContractViem(provider, network);
102
102
  return contract.read.getAllMarkets(setViemBlockNumber(block));
103
103
  });
104
- export const _getCompoundV2AccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () {
104
+ export const _getCompoundV2AccountBalances = (provider, network, block, addressMapping, address, tokens) => __awaiter(void 0, void 0, void 0, function* () {
105
105
  let balances = {
106
106
  collateral: {},
107
107
  debt: {},
@@ -109,7 +109,7 @@ export const _getCompoundV2AccountBalances = (provider, network, block, addressM
109
109
  if (!address) {
110
110
  return balances;
111
111
  }
112
- const assets = yield getAllMarketAddresses(provider, network, block);
112
+ const assets = tokens || (yield getAllMarketAddresses(provider, network, block));
113
113
  const assetInfo = assets.map(a => getAssetInfoByAddress(a, network));
114
114
  const loanInfoContract = CompoundLoanInfoContractViem(provider, network, block);
115
115
  const loanInfo = yield loanInfoContract.read.getTokenBalances([address, assets], setViemBlockNumber(block));
@@ -3,7 +3,7 @@ import { CrvUSDGlobalMarketData, CrvUSDMarketData, CrvUSDUserData } from '../typ
3
3
  import { Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances } from '../types/common';
4
4
  export declare const _getCurveUsdGlobalData: (provider: Client, network: NetworkNumber, selectedMarket: CrvUSDMarketData) => Promise<CrvUSDGlobalMarketData>;
5
5
  export declare const getCurveUsdGlobalData: (provider: EthereumProvider, network: NetworkNumber, selectedMarket: CrvUSDMarketData) => Promise<CrvUSDGlobalMarketData>;
6
- export declare const _getCrvUsdAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress) => Promise<PositionBalances>;
6
+ export declare const _getCrvUsdAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress, includeDeposited?: boolean) => Promise<PositionBalances>;
7
7
  export declare const getCrvUsdAccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress) => Promise<PositionBalances>;
8
8
  /**
9
9
  * @param borrowRate market borrow APY in % (`CrvUSDGlobalMarketData.borrowRate`); when omitted it is read from the view contract
@@ -99,7 +99,7 @@ const getStatusForUser = (bandRange, activeBand, crvUSDSupplied, collSupplied, h
99
99
  return CrvUSDStatus.SoftLiquidated; // or is fully soft liquidated
100
100
  return CrvUSDStatus.Nonexistant;
101
101
  };
102
- export const _getCrvUsdAccountBalances = (provider, network, block, addressMapping, address, controllerAddress) => __awaiter(void 0, void 0, void 0, function* () {
102
+ export const _getCrvUsdAccountBalances = (provider_1, network_1, block_1, addressMapping_1, address_1, controllerAddress_1, ...args_1) => __awaiter(void 0, [provider_1, network_1, block_1, addressMapping_1, address_1, controllerAddress_1, ...args_1], void 0, function* (provider, network, block, addressMapping, address, controllerAddress, includeDeposited = false) {
103
103
  let balances = {
104
104
  collateral: {},
105
105
  debt: {},
@@ -118,6 +118,11 @@ export const _getCrvUsdAccountBalances = (provider, network, block, addressMappi
118
118
  [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.debtAmount.toString(),
119
119
  },
120
120
  };
121
+ if (includeDeposited) {
122
+ balances.deposited = {
123
+ [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.curveUsdCollateralAmount.toString(),
124
+ };
125
+ }
121
126
  return balances;
122
127
  });
123
128
  export const getCrvUsdAccountBalances = (provider, network, block, addressMapping, address, controllerAddress) => __awaiter(void 0, void 0, void 0, function* () { return _getCrvUsdAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, controllerAddress); });
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import Dec from 'decimal.js';
11
11
  import { assetAmountInEth, getAssetInfo, getAssetInfoByAddress, } from '@defisaver/tokens';
12
+ import { fluidTokenAmount } from '../helpers/fluidBalances';
12
13
  import { IncentiveKind, NetworkNumber, } from '../types/common';
13
14
  import { FluidVaultType, } from '../types';
14
15
  import { BTCPriceFeedContractViem, DFSFeedRegistryContractViem, ETHPriceFeedContractViem, FeedRegistryContractViem, FluidViewContractViem, } from '../contracts';
@@ -925,8 +926,8 @@ const parseT1UserData = (userPositionData, vaultData) => {
925
926
  const collAsset = getAssetInfo(marketData.collAsset0);
926
927
  const debtAsset = getAssetInfo(marketData.debtAsset0);
927
928
  // for T2 and T4 - this is the number of shares
928
- const supplied = getEthAmountForDecimals(userPositionData.supply.toString(), collAsset.decimals);
929
- const borrowed = getEthAmountForDecimals(userPositionData.borrow.toString(), debtAsset.decimals);
929
+ const supplied = fluidTokenAmount(userPositionData.supply, collAsset.decimals);
930
+ const borrowed = fluidTokenAmount(userPositionData.borrow, debtAsset.decimals);
930
931
  const collUsedAsset = Object.assign(Object.assign({}, EMPTY_USED_ASSET), { symbol: collAsset.symbol, collateral: true, supplied, suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(), isSupplied: new Dec(supplied).gt(0) });
931
932
  const debtUsedAsset = Object.assign(Object.assign({}, EMPTY_USED_ASSET), { symbol: debtAsset.symbol, collateral: false, borrowed, borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(), isBorrowed: new Dec(borrowed).gt(0) });
932
933
  const usedAssets = {
@@ -946,9 +947,9 @@ const parseT2UserData = (userPositionData, vaultData) => {
946
947
  const collAsset1 = getAssetInfo(marketData.collAsset1);
947
948
  const debtAsset = getAssetInfo(marketData.debtAsset0);
948
949
  const supplyShares = getEthAmountForDecimals(userPositionData.supply.toString(), 18); // this is supplied in coll shares
949
- const borrowed = getEthAmountForDecimals(userPositionData.borrow.toString(), debtAsset.decimals); // this is actual token borrow
950
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare).toString();
951
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare).toString();
950
+ const borrowed = fluidTokenAmount(userPositionData.borrow, debtAsset.decimals); // this is actual token borrow
951
+ const supplied0 = fluidTokenAmount(userPositionData.supply, collAsset0.decimals, assetsData[collAsset0.symbol].tokenPerSupplyShare);
952
+ const supplied1 = fluidTokenAmount(userPositionData.supply, collAsset1.decimals, assetsData[collAsset1.symbol].tokenPerSupplyShare);
952
953
  const collUsedAsset0 = {
953
954
  symbol: collAsset0.symbol,
954
955
  collateral: true,
@@ -991,10 +992,10 @@ const parseT3UserData = (userPositionData, vaultData) => {
991
992
  const collAsset = getAssetInfo(marketData.collAsset0);
992
993
  const debtAsset0 = getAssetInfo(marketData.debtAsset0);
993
994
  const debtAsset1 = getAssetInfo(marketData.debtAsset1);
994
- const supplied = getEthAmountForDecimals(userPositionData.supply.toString(), collAsset.decimals); // this is actual token supply
995
+ const supplied = fluidTokenAmount(userPositionData.supply, collAsset.decimals); // this is actual token supply
995
996
  const borrowShares = getEthAmountForDecimals(userPositionData.borrow.toString(), 18); // this is actual token borrow
996
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare).toString();
997
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare).toString();
997
+ const borrowed0 = fluidTokenAmount(userPositionData.borrow, debtAsset0.decimals, assetsData[debtAsset0.symbol].tokenPerBorrowShare);
998
+ const borrowed1 = fluidTokenAmount(userPositionData.borrow, debtAsset1.decimals, assetsData[debtAsset1.symbol].tokenPerBorrowShare);
998
999
  const collUsedAsset = {
999
1000
  symbol: collAsset.symbol,
1000
1001
  collateral: true,
@@ -1039,10 +1040,10 @@ const parseT4UserData = (userPositionData, vaultData) => {
1039
1040
  const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1040
1041
  const supplyShares = getEthAmountForDecimals(userPositionData.supply.toString(), 18); // this is actual token supply
1041
1042
  const borrowShares = getEthAmountForDecimals(userPositionData.borrow.toString(), 18); // this is actual token borrow
1042
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare).toString();
1043
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare).toString();
1044
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare).toString();
1045
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare).toString();
1043
+ const supplied0 = fluidTokenAmount(userPositionData.supply, collAsset0.decimals, assetsData[collAsset0.symbol].tokenPerSupplyShare);
1044
+ const supplied1 = fluidTokenAmount(userPositionData.supply, collAsset1.decimals, assetsData[collAsset1.symbol].tokenPerSupplyShare);
1045
+ const borrowed0 = fluidTokenAmount(userPositionData.borrow, debtAsset0.decimals, assetsData[debtAsset0.symbol].tokenPerBorrowShare);
1046
+ const borrowed1 = fluidTokenAmount(userPositionData.borrow, debtAsset1.decimals, assetsData[debtAsset1.symbol].tokenPerBorrowShare);
1046
1047
  const collUsedAsset0 = {
1047
1048
  symbol: collAsset0.symbol,
1048
1049
  collateral: true,
@@ -0,0 +1,5 @@
1
+ import { Client } from 'viem';
2
+ import { AaveMarketInfo, SparkMarketData } from '../types';
3
+ import { Blockish, EthAddress, NetworkNumber, PositionBalances } from '../types/common';
4
+ /** Raw token balances shared by Aave/Spark getters and lending previews. */
5
+ export declare function getAaveLikeBalances(client: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, market: Pick<AaveMarketInfo | SparkMarketData, 'providerAddress' | 'protocolData' | 'protocolDataAddress'>, view: 'AaveLoanInfoV2' | 'AaveV3View' | 'SparkView', tokens?: EthAddress[]): Promise<PositionBalances>;
@@ -0,0 +1,45 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import Dec from 'decimal.js';
11
+ import { getAssetInfoByAddress } from '@defisaver/tokens';
12
+ import { createViemContractFromConfigFunc } from '../contracts';
13
+ import { setViemBlockNumber } from '../services/viem';
14
+ import { wethToEth, wethToEthByAddress } from '../services/utils';
15
+ /** Raw token balances shared by Aave/Spark getters and lending previews. */
16
+ export function getAaveLikeBalances(client, network, block, addressMapping, address, market, view, tokens) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const balances = { collateral: {}, debt: {} };
19
+ if (!address)
20
+ return balances;
21
+ let reserves;
22
+ if (tokens)
23
+ reserves = tokens.map(tokenAddress => ({ tokenAddress, symbol: getAssetInfoByAddress(tokenAddress, network).symbol }));
24
+ else {
25
+ if (!market.protocolData)
26
+ throw new Error('Missing protocol data provider');
27
+ reserves = [...yield createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(client, network)
28
+ .read.getAllReservesTokens(setViemBlockNumber(block))];
29
+ }
30
+ const addresses = reserves.map(token => token.tokenAddress);
31
+ const contract = createViemContractFromConfigFunc(view)(client, network, block);
32
+ const middle = tokens ? Math.ceil(addresses.length / 2) : Math.floor(addresses.length / 2);
33
+ // Preserve legacy V2 single-call and V3/Spark two-call behavior.
34
+ const parts = !tokens && view === 'AaveLoanInfoV2' ? [addresses] : [addresses.slice(0, middle), addresses.slice(middle)];
35
+ const data = (yield Promise.all((tokens ? parts.filter(part => part.length) : parts)
36
+ .map(part => contract.read.getTokenBalances([market.providerAddress, address, part], setViemBlockNumber(block))))).flat();
37
+ data.forEach((token, i) => {
38
+ // The views leave token.token unset; input order identifies the reserve.
39
+ const key = addressMapping ? wethToEthByAddress(reserves[i].tokenAddress, network).toLowerCase() : wethToEth(reserves[i].symbol);
40
+ balances.collateral[key] = token.balance.toString();
41
+ balances.debt[key] = new Dec(token.borrowsStable.toString()).add(token.borrowsVariable.toString()).toString();
42
+ });
43
+ return balances;
44
+ });
45
+ }
@@ -0,0 +1,6 @@
1
+ import { FluidUserPositionStructOutputStruct, FluidVaultDataStructOutputStruct } from '../types';
2
+ import { NetworkNumber, PositionBalances } from '../types/common';
3
+ /** Convert raw tokens, or raw 18-decimal shares with a human-readable token/share ratio. */
4
+ export declare const fluidTokenAmount: (amount: bigint, decimals: number, perShare?: string) => string;
5
+ /** The same token/share conversion used by the full Fluid user parsers, without prices or yield. */
6
+ export declare function parseFluidBalances(position: FluidUserPositionStructOutputStruct, vault: FluidVaultDataStructOutputStruct, network: NetworkNumber): PositionBalances;
@@ -0,0 +1,28 @@
1
+ import Dec from 'decimal.js';
2
+ import { getAssetInfoByAddress } from '@defisaver/tokens';
3
+ /** Convert raw tokens, or raw 18-decimal shares with a human-readable token/share ratio. */
4
+ export const fluidTokenAmount = (amount, decimals, perShare) => (new Dec(amount.toString()).div(new Dec(10).pow(perShare === undefined ? decimals : 18)).mul(perShare !== null && perShare !== void 0 ? perShare : 1).toString());
5
+ /** The same token/share conversion used by the full Fluid user parsers, without prices or yield. */
6
+ export function parseFluidBalances(position, vault, network) {
7
+ const type = Number(vault.vaultType);
8
+ if (![10000, 20000, 30000, 40000].includes(type))
9
+ throw new Error('Unsupported Fluid vault');
10
+ const side = (amount, tokens, ratios) => {
11
+ const balances = {};
12
+ tokens.forEach((address, i) => {
13
+ const token = getAssetInfoByAddress(address, network);
14
+ if (!Number.isFinite(token.decimals) || !token.symbol)
15
+ throw new Error('Fluid token metadata unavailable');
16
+ const perShare = ratios ? fluidTokenAmount(ratios[i], token.decimals) : undefined;
17
+ const value = fluidTokenAmount(amount, token.decimals, perShare);
18
+ balances[token.symbol] = new Dec(balances[token.symbol] || 0).add(value).toString();
19
+ });
20
+ return balances;
21
+ };
22
+ const smartSupply = type === 20000 || type === 40000;
23
+ const smartDebt = type === 30000 || type === 40000;
24
+ return {
25
+ collateral: side(position.supply, smartSupply ? [vault.supplyToken0, vault.supplyToken1] : [vault.supplyToken0], smartSupply ? [vault.dexSupplyData.token0PerSupplyShare, vault.dexSupplyData.token1PerSupplyShare] : undefined),
26
+ debt: side(position.borrow, smartDebt ? [vault.borrowToken0, vault.borrowToken1] : [vault.borrowToken0], smartDebt ? [vault.dexBorrowData.token0PerBorrowShare, vault.dexBorrowData.token1PerBorrowShare] : undefined),
27
+ };
28
+ }
@@ -11,6 +11,14 @@ export type SPYieldGainParameters = {
11
11
  };
12
12
  export declare const _getLiquityV2MarketData: (provider: Client, network: NetworkNumber, selectedMarket: LiquityV2MarketInfo) => Promise<LiquityV2MarketData>;
13
13
  export declare const getLiquityV2MarketData: (provider: EthereumProvider, network: NetworkNumber, selectedMarket: LiquityV2MarketInfo) => Promise<LiquityV2MarketData>;
14
+ export declare const nftContractCreationBlockMapping: {
15
+ liquityv2eth: number;
16
+ liquityv2wsteth: number;
17
+ liquityv2reth: number;
18
+ liquityv2ethlegacy: number;
19
+ liquityv2wstethlegacy: number;
20
+ liquityv2rethlegacy: number;
21
+ };
14
22
  export declare const _getLiquityV2UserTroveIds: (provider: PublicClient, network: NetworkNumber, selectedMarket: LiquityV2MarketInfo, troveNFTAddress: EthAddress, limitBlocksForEventFetching: boolean, account: EthAddress) => Promise<{
15
23
  troves: {
16
24
  troveId: string;
@@ -112,7 +112,7 @@ const getUserTroves = (provider_1, network_1, isLegacy_1, account_1, marketAddre
112
112
  return { troves: existingTroves.filter((trove) => trove.ownedByUser), nextFreeTroveIndex };
113
113
  return getUserTroves(provider, network, isLegacy, account, marketAddress, newStartIndex, newStartIndex + 100, existingTroves);
114
114
  });
115
- const nftContractCreationBlockMapping = {
115
+ export const nftContractCreationBlockMapping = {
116
116
  [LiquityV2Versions.LiquityV2Eth]: 22516079,
117
117
  [LiquityV2Versions.LiquityV2WstEth]: 22516099,
118
118
  [LiquityV2Versions.LiquityV2REth]: 22516118,
@@ -3,7 +3,7 @@ import { LlamaLendGlobalMarketData, LlamaLendMarketData, LlamaLendUserData } fro
3
3
  import { Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances } from '../types/common';
4
4
  export declare const _getLlamaLendGlobalData: (provider: Client, network: NetworkNumber, selectedMarket: LlamaLendMarketData) => Promise<LlamaLendGlobalMarketData>;
5
5
  export declare const getLlamaLendGlobalData: (provider: EthereumProvider, network: NetworkNumber, selectedMarket: LlamaLendMarketData) => Promise<LlamaLendGlobalMarketData>;
6
- export declare const _getLlamaLendAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress) => Promise<PositionBalances>;
6
+ export declare const _getLlamaLendAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress, includeDeposited?: boolean) => Promise<PositionBalances>;
7
7
  export declare const getLlamaLendAccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress) => Promise<PositionBalances>;
8
8
  export declare const _getLlamaLendUserData: (provider: Client, network: NetworkNumber, address: EthAddress, selectedMarket: LlamaLendMarketData, marketData: LlamaLendGlobalMarketData) => Promise<LlamaLendUserData>;
9
9
  export declare const getLlamaLendUserData: (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, selectedMarket: LlamaLendMarketData, marketData: LlamaLendGlobalMarketData) => Promise<LlamaLendUserData>;
@@ -153,7 +153,7 @@ const getStatusForUser = (bandRange, activeBand, debtSupplied, collSupplied, hea
153
153
  return LlamaLendStatus.SoftLiquidated; // or is fully soft liquidated
154
154
  return LlamaLendStatus.Nonexistant;
155
155
  };
156
- export const _getLlamaLendAccountBalances = (provider, network, block, addressMapping, address, controllerAddress) => __awaiter(void 0, void 0, void 0, function* () {
156
+ export const _getLlamaLendAccountBalances = (provider_1, network_1, block_1, addressMapping_1, address_1, controllerAddress_1, ...args_1) => __awaiter(void 0, [provider_1, network_1, block_1, addressMapping_1, address_1, controllerAddress_1, ...args_1], void 0, function* (provider, network, block, addressMapping, address, controllerAddress, includeDeposited = false) {
157
157
  let balances = {
158
158
  collateral: {},
159
159
  debt: {},
@@ -172,6 +172,11 @@ export const _getLlamaLendAccountBalances = (provider, network, block, addressMa
172
172
  [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.debtAmount.toString(),
173
173
  },
174
174
  };
175
+ if (includeDeposited) {
176
+ balances.deposited = {
177
+ [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.debtTokenCollateralAmount.toString(),
178
+ };
179
+ }
175
180
  return balances;
176
181
  });
177
182
  export const getLlamaLendAccountBalances = (provider, network, block, addressMapping, address, controllerAddress) => __awaiter(void 0, void 0, void 0, function* () { return _getLlamaLendAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, controllerAddress); });
@@ -5,7 +5,7 @@ export declare function _getMorphoMidnightMarketData(provider: Client, network:
5
5
  export declare function getMorphoMidnightMarketData(provider: EthereumProvider, network: NetworkNumber, selectedMarket: MorphoMidnightMarketData): Promise<MorphoMidnightMarketInfo>;
6
6
  export declare function _getMorphoMidnightAccountData(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<MorphoMidnightPositionData>;
7
7
  export declare function getMorphoMidnightAccountData(provider: EthereumProvider, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<MorphoMidnightPositionData>;
8
- export declare const _getMorphoMidnightAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData) => Promise<PositionBalances>;
8
+ export declare const _getMorphoMidnightAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData, includeCredit?: boolean) => Promise<PositionBalances>;
9
9
  export declare const getMorphoMidnightAccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData) => Promise<PositionBalances>;
10
10
  export declare function getMorphoMidnightEarn(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<{
11
11
  apy: string;
@@ -210,7 +210,7 @@ export function getMorphoMidnightAccountData(provider, network, account, selecte
210
210
  return _getMorphoMidnightAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo);
211
211
  });
212
212
  }
213
- export const _getMorphoMidnightAccountBalances = (provider, network, block, addressMapping, address, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () {
213
+ export const _getMorphoMidnightAccountBalances = (provider_1, network_1, block_1, addressMapping_1, address_1, selectedMarket_1, ...args_1) => __awaiter(void 0, [provider_1, network_1, block_1, addressMapping_1, address_1, selectedMarket_1, ...args_1], void 0, function* (provider, network, block, addressMapping, address, selectedMarket, includeCredit = false) {
214
214
  const balances = { collateral: {}, debt: {} };
215
215
  if (!address)
216
216
  return balances;
@@ -230,6 +230,11 @@ export const _getMorphoMidnightAccountBalances = (provider, network, block, addr
230
230
  collateral[addressMapping ? collInfo.address.toLowerCase() : wethToEth(collInfo.symbol)] = assetAmountInEth(rawAmount, wethToEth(collInfo.symbol));
231
231
  });
232
232
  balances.collateral = collateral;
233
+ if (includeCredit) {
234
+ balances.deposited = {
235
+ [addressMapping ? loanTokenInfo.address.toLowerCase() : wethToEth(loanTokenInfo.symbol)]: assetAmountInEth(positionInfo.credit.toString(), wethToEth(loanTokenInfo.symbol)),
236
+ };
237
+ }
233
238
  return balances;
234
239
  });
235
240
  export const getMorphoMidnightAccountBalances = (provider, network, block, addressMapping, address, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () { return _getMorphoMidnightAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, selectedMarket); });
@@ -11,3 +11,4 @@ export declare function getShifterPortfolioData(provider: EthereumProvider, netw
11
11
  markets: PortfolioMarketsData;
12
12
  }>;
13
13
  export * from './discovery';
14
+ export { getWalletLendingSummaries } from './lendingSummaries';
@@ -865,3 +865,4 @@ export function getShifterPortfolioData(provider_1, network_1, defaultProvider_1
865
865
  });
866
866
  }
867
867
  export * from './discovery';
868
+ export { getWalletLendingSummaries } from './lendingSummaries';
@@ -0,0 +1,7 @@
1
+ import { EthAddress, EthereumProvider, NetworkNumber } from '../types/common';
2
+ import { LendingSummaryOptions, WalletLendingSummaries } from '../types/lendingSummary';
3
+ /** Lending-only balances at one snapshot, valued with caller-supplied market prices.
4
+ * One shared client/limiter covers every wallet. Failed reads remain partial; cancellation
5
+ * discards results. Morpho Blue earn deposits, rewards and savings are excluded.
6
+ */
7
+ export declare function getWalletLendingSummaries(provider: EthereumProvider, network: NetworkNumber, walletAddresses: EthAddress[], options: LendingSummaryOptions): Promise<WalletLendingSummaries>;
@@ -0,0 +1,256 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ /* global BigInt */
11
+ import Dec from 'decimal.js';
12
+ import { getAssetInfo, getAssetInfoByAddress } from '@defisaver/tokens';
13
+ import { custom, parseAbi, parseAbiItem, } from 'viem';
14
+ import { AaveMarkets, AaveV4Spokes, CompoundMarkets, compoundV2CollateralAssets, CrvUsdMarkets, LiquityV2Markets, LlamaLendMarkets, MorphoBlueMarkets, MorphoMidnightMarkets, SparkMarkets, } from '../markets';
15
+ import { AaveVersions, CompoundVersions } from '../types';
16
+ import { NetworkNumber, } from '../types/common';
17
+ import { getConfigContractAbi, getConfigContractAddress } from '../contracts';
18
+ import { getViemProvider } from '../services/viem';
19
+ import { getWrappedNativeAssetFromUnwrapped } from '../services/utils';
20
+ import { getAaveLikeBalances } from '../helpers/aaveBalances';
21
+ import { parseFluidBalances } from '../helpers/fluidBalances';
22
+ import { _getAaveV4LoanBalances } from '../aaveV4';
23
+ import { _getCompoundV2AccountBalances } from '../compoundV2';
24
+ import { _getCompoundV3AccountBalances } from '../compoundV3';
25
+ import { _getCrvUsdAccountBalances } from '../curveUsd';
26
+ import { _getLlamaLendAccountBalances } from '../llamaLend';
27
+ import { _getMorphoBlueAccountBalances } from '../morphoBlue';
28
+ import { _getMorphoMidnightAccountBalances } from '../morphoMidnight';
29
+ import { _getLiquityAccountBalances } from '../liquity';
30
+ import { _getUserCdps } from '../maker';
31
+ import { nftContractCreationBlockMapping } from '../liquityV2';
32
+ import { lendingSummaryTransport } from './lendingSummaryTransport';
33
+ const nftAbi = parseAbi([
34
+ 'function troveNFT() view returns (address)', 'function balanceOf(address) view returns (uint256)',
35
+ 'function ownerOf(uint256) view returns (address)',
36
+ ]);
37
+ const transfer = parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)');
38
+ const units = (value, decimals = 18) => new Dec(String(value)).div(new Dec(10).pow(decimals)).toString();
39
+ const positive = (value) => new Dec(String(value)).gt(0);
40
+ const supported = (list, network) => Object.values(list).filter(m => m.chainIds.includes(network));
41
+ /** Lending-only balances at one snapshot, valued with caller-supplied market prices.
42
+ * One shared client/limiter covers every wallet. Failed reads remain partial; cancellation
43
+ * discards results. Morpho Blue earn deposits, rewards and savings are excluded.
44
+ */
45
+ export function getWalletLendingSummaries(provider, network, walletAddresses, options) {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ var _a, _b, _c, _d, _e;
48
+ const addresses = [...new Set(walletAddresses.map(address => {
49
+ if (!/^0x[0-9a-f]{40}$/i.test(address))
50
+ throw new Error('Invalid wallet address');
51
+ return address.toLowerCase();
52
+ }))];
53
+ const summaries = Object.fromEntries(addresses.map(address => [address, {
54
+ status: 'complete', positions: [], protocols: [], suppliedUsd: '0', valuationComplete: true, errors: [],
55
+ }]));
56
+ if (!addresses.length || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
57
+ return { summaries: {}, rateLimited: false };
58
+ const maxCalldataBytes = options.isSim ? 2000 : 32000;
59
+ const transport = lendingSummaryTransport(provider, options.signal, options.blockNumber, maxCalldataBytes);
60
+ const client = getViemProvider(transport.provider, network, {
61
+ transport: custom(transport.provider, { retryCount: 0 }), batch: { multicall: { batchSize: maxCalldataBytes } },
62
+ });
63
+ let snapshot;
64
+ try {
65
+ snapshot = (_b = options.blockNumber) !== null && _b !== void 0 ? _b : yield client.getBlockNumber();
66
+ transport.pinBlock(snapshot);
67
+ }
68
+ catch (error) {
69
+ if ((_c = options.signal) === null || _c === void 0 ? void 0 : _c.aborted)
70
+ return { summaries: {}, rateLimited: transport.isRateLimited() };
71
+ for (const summary of Object.values(summaries)) {
72
+ summary.status = 'failed';
73
+ summary.errors.push(String(error));
74
+ }
75
+ return { summaries, rateLimited: transport.isRateLimited() };
76
+ }
77
+ const block = Number(snapshot);
78
+ // Dynamic ABI boundary for user-scoped CDP/NFT reads; money markets use their existing readers.
79
+ const read = (name, functionName, args = []) => client.readContract({
80
+ address: getConfigContractAddress(name, network, block), abi: getConfigContractAbi(name, network, block), functionName, args,
81
+ });
82
+ const nftRead = (address, functionName, args = []) => client.readContract({
83
+ address, abi: nftAbi, functionName, args,
84
+ });
85
+ const cache = new Map();
86
+ const shared = (key, fetch) => {
87
+ if (!cache.has(key))
88
+ cache.set(key, fetch());
89
+ return cache.get(key);
90
+ };
91
+ const tasks = [];
92
+ const tokens = new Set();
93
+ const valuations = [];
94
+ let prices = {};
95
+ const run = (address, protocol, key, work) => __awaiter(this, void 0, void 0, function* () {
96
+ var _a;
97
+ try {
98
+ if (!((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
99
+ yield work();
100
+ }
101
+ catch (error) {
102
+ summaries[address].errors.push(`${protocol}:${key}: ${String(error).split('\n')[0]}`);
103
+ }
104
+ });
105
+ const add = (address_1, protocol_1, key_1, balances_1, ...args_1) => __awaiter(this, [address_1, protocol_1, key_1, balances_1, ...args_1], void 0, function* (address, protocol, key, balances, human = false) {
106
+ const supply = Object.entries(balances.collateral || {}).concat(Object.entries(balances.deposited || {}));
107
+ const debt = Object.entries(balances.debt || {});
108
+ if (![...supply, ...debt].some(([, amount]) => positive(amount)))
109
+ return;
110
+ const entry = {
111
+ id: `${protocol}:${key}`,
112
+ protocol,
113
+ suppliedUsd: (supply.some(([, amount]) => positive(amount)) ? null : '0'),
114
+ debtUsd: (debt.some(([, amount]) => positive(amount)) ? null : '0'),
115
+ };
116
+ summaries[address].positions.push(entry);
117
+ const normalize = (amounts) => {
118
+ const result = {};
119
+ amounts.filter(([, amount]) => positive(amount)).forEach(([symbol, amount]) => {
120
+ const token = symbol.startsWith('0x') ? getAssetInfoByAddress(symbol, network) : getAssetInfo(getWrappedNativeAssetFromUnwrapped(symbol), network);
121
+ if (!token.address || !Number.isFinite(token.decimals))
122
+ throw new Error(`Token metadata unavailable: ${symbol}`);
123
+ const id = token.address.toLowerCase();
124
+ tokens.add(id);
125
+ result[id] = (result[id] || new Dec(0)).add(human ? amount : units(amount, token.decimals));
126
+ });
127
+ return result;
128
+ };
129
+ const amounts = [normalize(supply), normalize(debt)];
130
+ valuations.push(() => {
131
+ ['suppliedUsd', 'debtUsd'].forEach((field, i) => {
132
+ try {
133
+ entry[field] = Object.entries(amounts[i]).reduce((total, [token, amount]) => {
134
+ const price = new Dec(prices[token] || 0);
135
+ if (!price.isFinite() || !price.gt(0))
136
+ throw new Error(`Price unavailable: ${token}`);
137
+ return total.add(amount.mul(price));
138
+ }, new Dec(0)).toString();
139
+ }
140
+ catch (error) {
141
+ summaries[address].errors.push(`${entry.id}: ${String(error)}`);
142
+ }
143
+ });
144
+ });
145
+ });
146
+ const balanceTask = (address, protocol, key, fetch, human = false) => tasks.push(run(address, protocol, key, () => __awaiter(this, void 0, void 0, function* () { return add(address, protocol, key, yield fetch(), human); })));
147
+ for (const address of addresses) {
148
+ const aaveMarkets = supported(AaveMarkets(network), network).filter(m => [AaveVersions.AaveV2, AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi].includes(m.value));
149
+ for (const market of [...aaveMarkets, ...supported(SparkMarkets(network), network)]) {
150
+ const v2 = market.value === AaveVersions.AaveV2;
151
+ const spark = !aaveMarkets.some(m => m.value === market.value);
152
+ balanceTask(address, spark ? 'spark' : v2 ? 'aaveV2' : 'aaveV3', market.value, () => getAaveLikeBalances(client, network, block, false, address, market, spark ? 'SparkView' : v2 ? 'AaveLoanInfoV2' : 'AaveV3View', market.assets.map(asset => getAssetInfo(getWrappedNativeAssetFromUnwrapped(asset), network).address)));
153
+ }
154
+ for (const spoke of supported(AaveV4Spokes(network), network)) {
155
+ balanceTask(address, 'aaveV4', spoke.value, () => __awaiter(this, void 0, void 0, function* () {
156
+ const { reserves } = yield _getAaveV4LoanBalances(client, network, block, address, spoke.address);
157
+ const balances = { collateral: {}, debt: {} };
158
+ reserves.forEach(r => {
159
+ balances.collateral[r.underlying] = new Dec(balances.collateral[r.underlying] || 0).add(r.supplied.toString()).toString();
160
+ balances.debt[r.underlying] = new Dec(balances.debt[r.underlying] || 0).add(r.totalDebt.toString()).toString();
161
+ });
162
+ return balances;
163
+ }));
164
+ }
165
+ for (const market of supported(CompoundMarkets(network), network)) {
166
+ const v2 = market.value === CompoundVersions.CompoundV2;
167
+ balanceTask(address, v2 ? 'compoundV2' : 'compoundV3', market.value, () => (v2
168
+ ? _getCompoundV2AccountBalances(client, network, block, false, address, compoundV2CollateralAssets.map(a => a.address))
169
+ : _getCompoundV3AccountBalances(client, network, block, false, address, market.baseMarketAddress)));
170
+ }
171
+ for (const market of supported(MorphoBlueMarkets(network), network))
172
+ balanceTask(address, 'morphoBlue', market.value, () => _getMorphoBlueAccountBalances(client, network, block, false, address, market), true);
173
+ for (const market of supported(MorphoMidnightMarkets(network), network))
174
+ balanceTask(address, 'morphoMidnight', market.value, () => _getMorphoMidnightAccountBalances(client, network, block, false, address, market, true), true);
175
+ if (network === NetworkNumber.Eth)
176
+ for (const market of supported(CrvUsdMarkets(network), network))
177
+ balanceTask(address, 'crvUsd', market.value, () => _getCrvUsdAccountBalances(client, network, block, false, address, market.controllerAddress, true));
178
+ if ([NetworkNumber.Eth, NetworkNumber.Arb].includes(network))
179
+ for (const market of supported(LlamaLendMarkets(network), network))
180
+ balanceTask(address, 'llamaLend', market.value, () => _getLlamaLendAccountBalances(client, network, block, false, address, market.controllerAddress, true));
181
+ if (network === NetworkNumber.Eth) {
182
+ balanceTask(address, 'liquity', 'trove', () => _getLiquityAccountBalances(client, network, block, false, address));
183
+ tasks.push(run(address, 'maker', 'discovery', () => __awaiter(this, void 0, void 0, function* () {
184
+ const cdps = yield _getUserCdps(client, network, address);
185
+ yield Promise.all(cdps.map(cdp => run(address, 'maker', String(cdp.id), () => __awaiter(this, void 0, void 0, function* () {
186
+ const [collateral, debt] = yield read('McdVat', 'urns', [cdp.ilk, cdp.urn]);
187
+ const rate = positive(debt) ? (yield shared(`maker:${cdp.ilk}`, () => read('McdVat', 'ilks', [cdp.ilk])))[1] : 0;
188
+ yield add(address, 'maker', String(cdp.id), { collateral: { [cdp.asset]: units(collateral) }, debt: { DAI: new Dec(units(debt)).mul(units(rate, 27)).toString() } }, true);
189
+ }))));
190
+ })));
191
+ for (const market of supported(LiquityV2Markets(network), network)) {
192
+ tasks.push(run(address, 'liquityV2', market.value, () => __awaiter(this, void 0, void 0, function* () {
193
+ const nft = yield shared(`nft:${market.value}`, () => nftRead(market.marketAddress, 'troveNFT'));
194
+ const count = yield nftRead(nft, 'balanceOf', [address]);
195
+ if (count === BigInt(0))
196
+ return;
197
+ const logs = yield client.getLogs({
198
+ address: nft, event: transfer, args: { to: address }, fromBlock: BigInt(nftContractCreationBlockMapping[market.value]), toBlock: snapshot,
199
+ });
200
+ const owned = (yield Promise.all([...new Set(logs.map(log => log.args.tokenId))].map((id) => __awaiter(this, void 0, void 0, function* () {
201
+ try {
202
+ return (yield nftRead(nft, 'ownerOf', [id])).toLowerCase() === address ? id : null;
203
+ }
204
+ catch (_a) {
205
+ return null;
206
+ }
207
+ })))).filter((id) => id !== null);
208
+ if (BigInt(owned.length) !== count)
209
+ summaries[address].errors.push(`liquityV2:${market.value}: Not all owned troves could be discovered`);
210
+ yield Promise.all(owned.map(id => run(address, 'liquityV2', `${market.value}:${id}`, () => __awaiter(this, void 0, void 0, function* () {
211
+ const data = yield read(market.isLegacy ? 'LiquityV2LegacyView' : 'LiquityV2View', 'getTroveInfo', [market.marketAddress, id]);
212
+ if (data.owner.toLowerCase() !== address)
213
+ throw new Error('Trove ownership changed');
214
+ yield add(address, 'liquityV2', `${market.value}:${id}`, { collateral: { [market.collateralToken]: data.collAmount.toString() }, debt: { [market.debtToken]: data.debtAmount.toString() } });
215
+ }))));
216
+ })));
217
+ }
218
+ }
219
+ if ([NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Base, NetworkNumber.Plasma].includes(network)) {
220
+ tasks.push(run(address, 'fluid', 'discovery', () => __awaiter(this, void 0, void 0, function* () {
221
+ const [positions, vaults] = yield read('FluidView', 'getUserPositions', [address]);
222
+ yield Promise.all(positions.map((p, i) => run(address, 'fluid', String(p.nftId), () => __awaiter(this, void 0, void 0, function* () {
223
+ if (positive(p.supply) || positive(p.borrow))
224
+ yield add(address, 'fluid', String(p.nftId), parseFluidBalances(p, vaults[i], network), true);
225
+ }))));
226
+ })));
227
+ }
228
+ }
229
+ yield Promise.all(tasks);
230
+ if ((_d = options.signal) === null || _d === void 0 ? void 0 : _d.aborted)
231
+ return { summaries: {}, rateLimited: transport.isRateLimited() };
232
+ if (tokens.size) {
233
+ try {
234
+ prices = yield options.resolvePrices(network, [...tokens], options.signal);
235
+ }
236
+ catch (error) {
237
+ for (const summary of Object.values(summaries))
238
+ if (summary.positions.length)
239
+ summary.errors.push(`Prices: ${String(error)}`);
240
+ }
241
+ }
242
+ if ((_e = options.signal) === null || _e === void 0 ? void 0 : _e.aborted)
243
+ return { summaries: {}, rateLimited: transport.isRateLimited() };
244
+ valuations.forEach(value => value());
245
+ for (const summary of Object.values(summaries)) {
246
+ summary.positions.sort((a, b) => a.id.localeCompare(b.id));
247
+ summary.protocols = [...new Set(summary.positions.map(p => p.protocol))];
248
+ summary.suppliedUsd = summary.positions.reduce((total, p) => total.add(p.suppliedUsd || 0), new Dec(0)).toString();
249
+ summary.valuationComplete = summary.positions.every(p => p.suppliedUsd !== null && p.debtUsd !== null);
250
+ summary.errors = [...new Set(summary.errors)];
251
+ if (summary.errors.length)
252
+ summary.status = 'partial';
253
+ }
254
+ return { summaries, rateLimited: transport.isRateLimited() };
255
+ });
256
+ }
@@ -0,0 +1,8 @@
1
+ import { EthereumProvider } from '../types/common';
2
+ export declare const isLendingSummaryRateLimit: (error: unknown) => boolean;
3
+ /** One limiter for all reads, including split multicalls. No retries after cancellation/429. */
4
+ export declare function lendingSummaryTransport(provider: EthereumProvider, signal?: AbortSignal, blockNumber?: bigint, maxCalldataBytes?: number): {
5
+ provider: EthereumProvider;
6
+ isRateLimited: () => boolean;
7
+ pinBlock: (value: bigint) => void;
8
+ };