@defisaver/positions-sdk 2.1.168-stable-pair-dev → 2.1.169-custom-fetching-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.
@@ -110,6 +110,7 @@ export declare enum MorphoBlueVersions {
110
110
  MorphoBlueUSDeUSDC_915_Base = "morphoblueusdeusdc_915_base",// USDe/USDC 0.915
111
111
  MorphoBlueCbEthUSDC_770_Base = "morphobluecbethusdc_770_base",// cbETH/USDC 0.77
112
112
  MorphoBlueCbXRPUSDC_625_Base = "morphobluecbxrpusdc_625_base",// cbXRP/USDC 0.625
113
+ MorphoBlueCbHYPEUSDC_625_Base = "morphobluecbhypeusdc_625_base",// cbHYPE/USDC 0.625
113
114
  MorphoBlueSyrupUSDCUSDC_915_Arb = "morphobluesyrupusdcusdc_915_arb",// syrupUSDC/USDC
114
115
  MorphoBlueWBTCUSDC_860_Arb = "morphobluewbtcusdc_860_arb",// WBTC/USDC
115
116
  MorphoBlueWstEthUSDC_860_Arb = "morphobluewstethusdc_860_arb",// wstETH/USDC
@@ -117,6 +117,7 @@ export var MorphoBlueVersions;
117
117
  MorphoBlueVersions["MorphoBlueUSDeUSDC_915_Base"] = "morphoblueusdeusdc_915_base";
118
118
  MorphoBlueVersions["MorphoBlueCbEthUSDC_770_Base"] = "morphobluecbethusdc_770_base";
119
119
  MorphoBlueVersions["MorphoBlueCbXRPUSDC_625_Base"] = "morphobluecbxrpusdc_625_base";
120
+ MorphoBlueVersions["MorphoBlueCbHYPEUSDC_625_Base"] = "morphobluecbhypeusdc_625_base";
120
121
  // ARBITRUM
121
122
  MorphoBlueVersions["MorphoBlueSyrupUSDCUSDC_915_Arb"] = "morphobluesyrupusdcusdc_915_arb";
122
123
  MorphoBlueVersions["MorphoBlueWBTCUSDC_860_Arb"] = "morphobluewbtcusdc_860_arb";
@@ -60,6 +60,40 @@ export interface PortfolioPositionsDataForAddress {
60
60
  export interface PortfolioPositionsData {
61
61
  [key: EthAddress]: PortfolioPositionsDataForAddress;
62
62
  }
63
+ export declare enum PortfolioProtocol {
64
+ AaveV2 = "aaveV2",
65
+ AaveV3 = "aaveV3",
66
+ AaveV4 = "aaveV4",
67
+ CompoundV2 = "compoundV2",
68
+ CompoundV3 = "compoundV3",
69
+ Spark = "spark",
70
+ MorphoBlue = "morphoBlue",
71
+ MorphoMidnight = "morphoMidnight",
72
+ CrvUsd = "crvUsd",
73
+ LlamaLend = "llamaLend",
74
+ Maker = "maker",
75
+ Liquity = "liquity",
76
+ LiquityV2 = "liquityV2",
77
+ Fluid = "fluid"
78
+ }
79
+ export interface CustomDeFiDataOptions {
80
+ /** Defaults to every protocol. */
81
+ protocols?: PortfolioProtocol[];
82
+ fetchStaking?: boolean;
83
+ fetchRewards?: boolean;
84
+ /** Keep Aave V3 / Spark positions with no supply so the eMode category is available. */
85
+ returnEmptyEModePositions?: boolean;
86
+ fetchFluidMarkets?: boolean;
87
+ isSim?: boolean;
88
+ /** viem multicall calldata cap in bytes; defaults to 250k (2k when isSim). */
89
+ batchSize?: number;
90
+ }
91
+ export interface CustomDeFiData {
92
+ positions: PortfolioPositionsData;
93
+ stakingPositions: Record<string, any>;
94
+ rewardsData: Record<string, any>;
95
+ markets: PortfolioMarketsData;
96
+ }
63
97
  export interface PortfolioMarketsData {
64
98
  morphoMarketsData: Record<string, MorphoBlueMarketInfo>;
65
99
  morphoMidnightMarketsData: Record<string, MorphoMidnightMarketInfo>;
@@ -1 +1,17 @@
1
- export {};
1
+ export var PortfolioProtocol;
2
+ (function (PortfolioProtocol) {
3
+ PortfolioProtocol["AaveV2"] = "aaveV2";
4
+ PortfolioProtocol["AaveV3"] = "aaveV3";
5
+ PortfolioProtocol["AaveV4"] = "aaveV4";
6
+ PortfolioProtocol["CompoundV2"] = "compoundV2";
7
+ PortfolioProtocol["CompoundV3"] = "compoundV3";
8
+ PortfolioProtocol["Spark"] = "spark";
9
+ PortfolioProtocol["MorphoBlue"] = "morphoBlue";
10
+ PortfolioProtocol["MorphoMidnight"] = "morphoMidnight";
11
+ PortfolioProtocol["CrvUsd"] = "crvUsd";
12
+ PortfolioProtocol["LlamaLend"] = "llamaLend";
13
+ PortfolioProtocol["Maker"] = "maker";
14
+ PortfolioProtocol["Liquity"] = "liquity";
15
+ PortfolioProtocol["LiquityV2"] = "liquityV2";
16
+ PortfolioProtocol["Fluid"] = "fluid";
17
+ })(PortfolioProtocol || (PortfolioProtocol = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "2.1.168-stable-pair-dev",
3
+ "version": "2.1.169-custom-fetching-dev",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -22,7 +22,7 @@
22
22
  "repository": "https://github.com/defisaver/defisaver-positions-sdk",
23
23
  "license": "ISC",
24
24
  "dependencies": {
25
- "@defisaver/tokens": "^1.7.45",
25
+ "@defisaver/tokens": "^1.7.50",
26
26
  "@types/lodash": "^4.17.15",
27
27
  "@types/memoizee": "^0.4.12",
28
28
  "decimal.js": "^10.6.0",
@@ -1659,6 +1659,21 @@ export const MORPHO_BLUE_CBXRP_USDC_625_BASE = (networkId: NetworkNumber = Netwo
1659
1659
  marketId: '0xd4a903dc6d949519060c7707f9604fdc9772c046e05c2e3a8fce0bd7196e4109',
1660
1660
  protocolName: 'morpho-blue',
1661
1661
  });
1662
+ export const MORPHO_BLUE_CBHYPE_USDC_625_BASE = (networkId: NetworkNumber = NetworkNumber.Base): MorphoBlueMarketData => ({
1663
+ chainIds: [NetworkNumber.Base],
1664
+ label: 'Morpho Blue',
1665
+ shortLabel: 'cbHYPE/USDC',
1666
+ value: MorphoBlueVersions.MorphoBlueCbHYPEUSDC_625_Base,
1667
+ url: 'cbhypeusdc-76629002',
1668
+ loanToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
1669
+ collateralToken: '0xB200000000000000000000451d033a5000cb479e',
1670
+ oracle: '0x7FaD8B8De2DDb7b4B415e1Aa3613e45EeF9E4bFf',
1671
+ oracleType: MorphoBlueOracleType.MARKET_RATE,
1672
+ irm: '0x46415998764C29aB2a25CbeA6254146D50D22687',
1673
+ lltv: 0.625,
1674
+ marketId: '0x76629002c9fdb20fb2092053a4f22c5c65e04a81887218b9546f2a2d82b4c0a8',
1675
+ protocolName: 'morpho-blue',
1676
+ });
1662
1677
 
1663
1678
  // ARBITRUM
1664
1679
  export const MORPHO_BLUE_SYRUPUSDC_USDC_915_ARB = (networkId: NetworkNumber = NetworkNumber.Eth): MorphoBlueMarketData => ({
@@ -1935,6 +1950,7 @@ export const MorphoBlueMarkets = (networkId: NetworkNumber) => ({
1935
1950
  [MorphoBlueVersions.MorphoBlueUSDeUSDC_915_Base]: MORPHO_BLUE_USDE_USDC_915_BASE(networkId),
1936
1951
  [MorphoBlueVersions.MorphoBlueCbEthUSDC_770_Base]: MORPHO_BLUE_CBETH_USDC_770_BASE(networkId),
1937
1952
  [MorphoBlueVersions.MorphoBlueCbXRPUSDC_625_Base]: MORPHO_BLUE_CBXRP_USDC_625_BASE(networkId),
1953
+ [MorphoBlueVersions.MorphoBlueCbHYPEUSDC_625_Base]: MORPHO_BLUE_CBHYPE_USDC_625_BASE(networkId),
1938
1954
  [MorphoBlueVersions.MorphoBlueWsuperOETHbWETH_915_Base]: MORPHO_BLUE_WSUPEROETHB_WETH_915_BASE(networkId),
1939
1955
  [MorphoBlueVersions.MorphoBlueCbEthEth_945_Base]: MORPHO_BLUE_CBETH_ETH_945_BASE(networkId),
1940
1956
  [MorphoBlueVersions.MorphoBlueCbEthEth_965_Base]: MORPHO_BLUE_CBETH_ETH_965_BASE(networkId),
@@ -0,0 +1,378 @@
1
+ import Dec from 'decimal.js';
2
+ import { EthAddress, EthereumProvider, NetworkNumber } from '../types/common';
3
+ import {
4
+ AaveMarkets,
5
+ AaveV4Spokes,
6
+ CompoundMarkets,
7
+ CrvUsdMarkets,
8
+ LiquityV2Markets,
9
+ LlamaLendMarkets,
10
+ MakerActiveIlks,
11
+ MorphoBlueMarkets,
12
+ MorphoMidnightMarkets,
13
+ SparkMarkets,
14
+ } from '../markets';
15
+ import {
16
+ AaveVersions,
17
+ CdpInfo,
18
+ CompoundVersions,
19
+ CustomDeFiData,
20
+ CustomDeFiDataOptions,
21
+ PortfolioMarketsData,
22
+ PortfolioPositionsData,
23
+ PortfolioProtocol,
24
+ } from '../types';
25
+ import { getViemProvider } from '../services/viem';
26
+ import { ZERO_ADDRESS } from '../constants';
27
+ import { _getAaveV2AccountData, _getAaveV2MarketsData } from '../aaveV2';
28
+ import { _getAaveV3AccountData, _getAaveV3MarketData, getStakeAaveData } from '../aaveV3';
29
+ import { _getAaveV4AccountData, _getAaveV4SpokeData } from '../aaveV4';
30
+ import { _getCompoundV2AccountData, _getCompoundV2MarketsData } from '../compoundV2';
31
+ import { _getCompoundV3AccountData, _getCompoundV3MarketsData } from '../compoundV3';
32
+ import { _getSparkAccountData, _getSparkMarketsData } from '../spark';
33
+ import { _getCurveUsdGlobalData, _getCurveUsdUserData } from '../curveUsd';
34
+ import { _getLlamaLendGlobalData, _getLlamaLendUserData } from '../llamaLend';
35
+ import { _getMorphoBlueAccountData, _getMorphoBluePortfolioMarketData, getMorphoEarn } from '../morphoBlue';
36
+ import { _getMorphoMidnightAccountData, _getMorphoMidnightMarketData } from '../morphoMidnight';
37
+ import { _getMakerCdpData, _getMakerIlksData, _getUserCdps } from '../maker';
38
+ import { _getLiquityTroveInfo, getLiquityStakingData } from '../liquity';
39
+ import { _getLiquityV2MarketData, getLiquitySAndYBold, getLiquityV2Staking } from '../liquityV2';
40
+ import { _getAllFluidMarketDataPortfolio, _getAllUserEarnPositionsWithFTokens, _getUserPositionsPortfolio } from '../fluid';
41
+ import { getUmbrellaData } from '../umbrella';
42
+ import { getMerklUnclaimedRewards, getUnclaimedRewardsForAllMarkets } from '../claiming/aaveV3';
43
+ import { fetchSparkAirdropRewards, fetchSparkRewards } from '../claiming/spark';
44
+ import { getKingRewards } from '../claiming/king';
45
+ import { fetchEthenaAirdropRewards } from '../claiming/ethena';
46
+ import { getUniswapRewards } from '../claiming/uniswap';
47
+
48
+ const lower = (address: EthAddress) => address.toLowerCase() as EthAddress;
49
+ const positive = (value: string | undefined) => new Dec(value || '0').gt(0);
50
+
51
+ const supported = <T extends { chainIds: NetworkNumber[] }>(list: Record<string, T>, network: NetworkNumber) => (
52
+ Object.values(list).filter((m) => m.chainIds.includes(network))
53
+ );
54
+
55
+ export async function getCustomDeFiData(
56
+ provider: EthereumProvider,
57
+ network: NetworkNumber,
58
+ defaultProvider: EthereumProvider,
59
+ addresses: EthAddress[],
60
+ options: CustomDeFiDataOptions = {},
61
+ ): Promise<CustomDeFiData> {
62
+ const {
63
+ protocols = Object.values(PortfolioProtocol),
64
+ fetchStaking = false,
65
+ fetchRewards = false,
66
+ returnEmptyEModePositions = false,
67
+ fetchFluidMarkets = false,
68
+ isSim = false,
69
+ } = options;
70
+ // JSON-RPC body ends up ~4x the calldata cap; 250k keeps it under the ~2.5MB provider limit.
71
+ const batchSize = options.batchSize ?? (isSim ? 2_000 : 250_000);
72
+ const has = (protocol: PortfolioProtocol) => protocols.includes(protocol);
73
+
74
+ const isMainnet = network === NetworkNumber.Eth;
75
+ const isFluidSupported = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Base, NetworkNumber.Plasma].includes(network);
76
+
77
+ const client = getViemProvider(provider, network, { batch: { multicall: { batchSize } } });
78
+ const defaultClient = getViemProvider(defaultProvider, network, { batch: { multicall: { batchSize } } });
79
+
80
+ const aaveV3Markets = has(PortfolioProtocol.AaveV3)
81
+ ? [AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi].map((v) => AaveMarkets(network)[v]).filter((m) => m.chainIds.includes(network))
82
+ : [];
83
+ const aaveV2Markets = has(PortfolioProtocol.AaveV2) ? [AaveMarkets(network)[AaveVersions.AaveV2]].filter((m) => m.chainIds.includes(network)) : [];
84
+ const aaveV4Spokes = has(PortfolioProtocol.AaveV4) ? supported(AaveV4Spokes(network), network) : [];
85
+ const compoundV3Markets = has(PortfolioProtocol.CompoundV3) ? supported(CompoundMarkets(network), network).filter((m) => m.value !== CompoundVersions.CompoundV2) : [];
86
+ const compoundV2Markets = has(PortfolioProtocol.CompoundV2) ? [CompoundMarkets(network)[CompoundVersions.CompoundV2]].filter((m) => m.chainIds.includes(network)) : [];
87
+ const sparkMarkets = has(PortfolioProtocol.Spark) ? supported(SparkMarkets(network), network) : [];
88
+ const morphoMarkets = has(PortfolioProtocol.MorphoBlue) ? supported(MorphoBlueMarkets(network), network) : [];
89
+ const morphoMidnightMarkets = has(PortfolioProtocol.MorphoMidnight) ? supported(MorphoMidnightMarkets(network), network) : [];
90
+ const crvUsdMarkets = has(PortfolioProtocol.CrvUsd) ? supported(CrvUsdMarkets(network), network) : [];
91
+ const llamaLendMarkets = has(PortfolioProtocol.LlamaLend) && [NetworkNumber.Eth, NetworkNumber.Arb].includes(network) ? supported(LlamaLendMarkets(network), network) : [];
92
+ const liquityV2Markets = has(PortfolioProtocol.LiquityV2) && isMainnet ? Object.values(LiquityV2Markets(network)) : [];
93
+ const liquityV2StakingMarkets = liquityV2Markets.filter((m) => !m.isLegacy);
94
+ const fetchMaker = has(PortfolioProtocol.Maker) && isMainnet;
95
+ const fetchLiquity = has(PortfolioProtocol.Liquity) && isMainnet;
96
+ const fetchFluid = has(PortfolioProtocol.Fluid) && isFluidSupported;
97
+
98
+ const markets: PortfolioMarketsData = {
99
+ morphoMarketsData: {},
100
+ morphoMidnightMarketsData: {},
101
+ compoundV3MarketsData: {},
102
+ sparkMarketsData: {},
103
+ aaveV3MarketsData: {},
104
+ aaveV2MarketsData: {},
105
+ compoundV2MarketsData: {},
106
+ crvUsdMarketsData: {},
107
+ llamaLendMarketsData: {},
108
+ liquityV2MarketsData: {},
109
+ aaveV4SpokesData: {},
110
+ fluidMarketsData: {},
111
+ makerMarketsData: {},
112
+ };
113
+ const makerCdps: Record<string, CdpInfo[]> = {};
114
+ const positions: PortfolioPositionsData = {};
115
+ const stakingPositions: Record<string, any> = {};
116
+ const rewardsData: Record<string, any> = {};
117
+
118
+ for (const address of addresses) {
119
+ positions[lower(address)] = {
120
+ aaveV3: {},
121
+ aaveV4: {},
122
+ morphoBlue: {},
123
+ morphoMidnight: {},
124
+ compoundV3: {},
125
+ spark: {},
126
+ maker: {},
127
+ aaveV2: {},
128
+ compoundV2: {},
129
+ liquity: {},
130
+ crvUsd: {},
131
+ llamaLend: {},
132
+ fluid: { error: '', data: {} },
133
+ };
134
+ if (fetchStaking) {
135
+ stakingPositions[lower(address)] = {
136
+ aaveV3: {}, morphoBlue: {}, liquity: {}, liquityV2: {}, fluid: { error: '', data: {} },
137
+ };
138
+ }
139
+ if (fetchRewards) {
140
+ rewardsData[lower(address)] = {
141
+ merkl: {}, aaveV3: {}, spark: {}, spk: {}, king: {}, ethena: {}, uniswap: {},
142
+ };
143
+ }
144
+ }
145
+
146
+ const run = async <T>(label: string, fetch: () => Promise<T>, store: (data: T) => void, onError: (err: { error: string, data: null }) => void) => {
147
+ try {
148
+ store(await fetch());
149
+ } catch (error) {
150
+ console.error(`Error fetching ${label}:`, error);
151
+ onError({ error: `Error fetching ${label}`, data: null });
152
+ }
153
+ };
154
+
155
+ const perAddress = <M>(list: M[], task: (market: M, address: EthAddress) => Promise<void>) => list.map((m) => addresses.map((a) => task(m, a))).flat();
156
+
157
+ const batchRewards = (key: string, label: string, fetch: () => Promise<Record<string, any>>, enabled = true) => (async () => {
158
+ if (!enabled) {
159
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: '', data: [] };
160
+ return;
161
+ }
162
+ try {
163
+ const result = await fetch();
164
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: '', data: result[lower(address)] || [] };
165
+ } catch (error) {
166
+ console.error(`Error fetching ${label}:`, error);
167
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: `Error fetching ${label}`, data: null };
168
+ }
169
+ })();
170
+
171
+ await Promise.allSettled([
172
+ ...morphoMarkets.map(async (m) => { markets.morphoMarketsData[m.value] = await _getMorphoBluePortfolioMarketData(client, network, m); }),
173
+ ...morphoMidnightMarkets.map(async (m) => { markets.morphoMidnightMarketsData[m.value] = await _getMorphoMidnightMarketData(client, network, m); }),
174
+ ...compoundV3Markets.map(async (m) => { markets.compoundV3MarketsData[m.value] = await _getCompoundV3MarketsData(client, network, m, defaultClient); }),
175
+ ...sparkMarkets.map(async (m) => { markets.sparkMarketsData[m.value] = await _getSparkMarketsData(client, network, m); }),
176
+ ...aaveV3Markets.map(async (m) => { markets.aaveV3MarketsData[m.value] = await _getAaveV3MarketData(client, network, m); }),
177
+ ...aaveV4Spokes.map(async (s) => { markets.aaveV4SpokesData[s.value] = await _getAaveV4SpokeData(client, network, s); }),
178
+ ...aaveV2Markets.map(async (m) => { markets.aaveV2MarketsData[m.value] = await _getAaveV2MarketsData(client, network, m); }),
179
+ ...compoundV2Markets.map(async (m) => { markets.compoundV2MarketsData[m.value] = await _getCompoundV2MarketsData(client, network); }),
180
+ ...crvUsdMarkets.map(async (m) => { markets.crvUsdMarketsData[m.value] = await _getCurveUsdGlobalData(client, network, m); }),
181
+ ...llamaLendMarkets.map(async (m) => { markets.llamaLendMarketsData[m.value] = await _getLlamaLendGlobalData(client, network, m); }),
182
+ ...liquityV2Markets.map(async (m) => { markets.liquityV2MarketsData[m.value] = await _getLiquityV2MarketData(client, network, m); }),
183
+ (async () => {
184
+ if (!fetchFluid || !fetchFluidMarkets) return;
185
+ try { markets.fluidMarketsData = await _getAllFluidMarketDataPortfolio(client, network); } catch (error) { console.error('Error fetching Fluid markets data:', error); }
186
+ })(),
187
+ (async () => {
188
+ if (!fetchMaker) return;
189
+ try { markets.makerMarketsData = await _getMakerIlksData(client, network, MakerActiveIlks); } catch (error) { console.error('Error fetching Maker ilks data:', error); }
190
+ })(),
191
+
192
+ ...addresses.map(async (address) => {
193
+ if (!fetchMaker) return;
194
+ makerCdps[lower(address)] = await _getUserCdps(client, network, address);
195
+ }),
196
+ ...addresses.map((address) => fetchFluid && run(
197
+ `Fluid positions for address ${address}`,
198
+ () => _getUserPositionsPortfolio(client, network, address),
199
+ (userPositions) => {
200
+ for (const position of userPositions) {
201
+ if (position.userData && positive(position.userData.suppliedUsd)) positions[lower(address)].fluid.data[position.userData.nftId] = position.userData;
202
+ }
203
+ },
204
+ (err) => { positions[lower(address)].fluid = { error: err.error, data: {} }; },
205
+ )),
206
+
207
+ ...(fetchStaking ? [
208
+ ...addresses.map((address) => fetchFluid && run(
209
+ `Fluid lend data for address ${address}`,
210
+ () => _getAllUserEarnPositionsWithFTokens(client, network, address),
211
+ (data) => { stakingPositions[lower(address)].fluid = data; },
212
+ (err) => { stakingPositions[lower(address)].fluid = err; },
213
+ )),
214
+ ...addresses.map((address) => fetchLiquity && run(
215
+ `Liquity staking data for address ${address}`,
216
+ () => getLiquityStakingData(client, network, address),
217
+ (data) => { stakingPositions[lower(address)].liquity = data; },
218
+ (err) => { stakingPositions[lower(address)].liquity = err; },
219
+ )),
220
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(
221
+ `Aave V3 staking data for address ${address}`,
222
+ () => getStakeAaveData(client, network, address),
223
+ (data) => { stakingPositions[lower(address)].aaveV3 = data; },
224
+ (err) => { stakingPositions[lower(address)].aaveV3 = err; },
225
+ )),
226
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(
227
+ `Umbrella staking data for address ${address}`,
228
+ () => getUmbrellaData(client, network, address),
229
+ (data) => { stakingPositions[lower(address)].umbrella = data; },
230
+ (err) => { stakingPositions[lower(address)].umbrella = err; },
231
+ )),
232
+ ...perAddress(liquityV2StakingMarkets, (market, address) => run(
233
+ `Liquity V2 staking data for address ${address}, market ${market.value}`,
234
+ () => getLiquityV2Staking(client, network, market.value, address),
235
+ (data) => { stakingPositions[lower(address)].liquityV2[market.value] = { error: '', data }; },
236
+ (err) => { stakingPositions[lower(address)].liquityV2[market.value] = err; },
237
+ )),
238
+ ] : []),
239
+
240
+ ...(fetchRewards ? [
241
+ batchRewards('king', 'King rewards data', () => getKingRewards(client, network, addresses), isMainnet),
242
+ batchRewards('uniswap', 'Uniswap rewards data', () => getUniswapRewards(client, network, addresses), isMainnet),
243
+ batchRewards('spk', 'Spark Airdrop rewards data', () => fetchSparkAirdropRewards(client, network, addresses), isMainnet && has(PortfolioProtocol.Spark)),
244
+ batchRewards('ethena', 'Ethena Airdrop rewards data', () => fetchEthenaAirdropRewards(addresses), isMainnet),
245
+ ...addresses.map((address) => run(
246
+ `Merkl rewards data for address ${address}`,
247
+ () => getMerklUnclaimedRewards(address, network),
248
+ (data) => { rewardsData[lower(address)].merkl = { error: '', data }; },
249
+ (err) => { rewardsData[lower(address)].merkl = err; },
250
+ )),
251
+ ...perAddress(aaveV3Markets, (market, address) => run(
252
+ `Aave V3 rewards data for address ${address}, market ${market.value}`,
253
+ () => getUnclaimedRewardsForAllMarkets(client, network, address, market.providerAddress),
254
+ (data) => { rewardsData[lower(address)].aaveV3[market.value] = { error: '', data }; },
255
+ (err) => { rewardsData[lower(address)].aaveV3[market.value] = err; },
256
+ )),
257
+ ...perAddress(sparkMarkets, (market, address) => {
258
+ if (!isMainnet) {
259
+ rewardsData[lower(address)].spark[market.value] = { error: '', data: [] };
260
+ return Promise.resolve();
261
+ }
262
+ return run(
263
+ `Spark rewards data for address ${address}, market ${market.value}`,
264
+ () => fetchSparkRewards(client, network, address, market.providerAddress),
265
+ (data) => { rewardsData[lower(address)].spark[market.value] = { error: '', data }; },
266
+ (err) => { rewardsData[lower(address)].spark[market.value] = err; },
267
+ );
268
+ }),
269
+ ] : []),
270
+ ]);
271
+
272
+ await Promise.all([
273
+ ...perAddress(aaveV3Markets, (market, address) => run(
274
+ `AaveV3 account data for address ${address} on market ${market.value}`,
275
+ () => _getAaveV3AccountData(client, network, address, { selectedMarket: market, ...markets.aaveV3MarketsData[market.value] }),
276
+ (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd)) positions[lower(address)].aaveV3[market.value] = { error: '', data }; },
277
+ (err) => { positions[lower(address)].aaveV3[market.value] = err; },
278
+ )),
279
+ ...perAddress(sparkMarkets, (market, address) => run(
280
+ `Spark account data for address ${address} on market ${market.value}`,
281
+ () => _getSparkAccountData(client, network, address, { selectedMarket: market, assetsData: markets.sparkMarketsData[market.value].assetsData, eModeCategoriesData: markets.sparkMarketsData[market.value].eModeCategoriesData }),
282
+ (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd)) positions[lower(address)].spark[market.value] = { error: '', data }; },
283
+ (err) => { positions[lower(address)].spark[market.value] = err; },
284
+ )),
285
+ ...perAddress(aaveV4Spokes, (spoke, address) => run(
286
+ `AaveV4 account data for address ${address} on spoke ${spoke.value}`,
287
+ () => _getAaveV4AccountData(client, network, markets.aaveV4SpokesData[spoke.value], address),
288
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].aaveV4[spoke.value] = { error: '', data }; },
289
+ (err) => { positions[lower(address)].aaveV4[spoke.value] = err; },
290
+ )),
291
+ ...perAddress(morphoMarkets, (market, address) => run(
292
+ `MorphoBlue account data for address ${address} on market ${market.value}`,
293
+ () => _getMorphoBlueAccountData(client, network, address, market, markets.morphoMarketsData[market.value]),
294
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].morphoBlue[market.value] = { error: '', data }; },
295
+ (err) => { positions[lower(address)].morphoBlue[market.value] = err; },
296
+ )),
297
+ ...(fetchStaking ? perAddress(morphoMarkets, (market, address) => run(
298
+ `MorphoBlue earn data for address ${address} on market ${market.value}`,
299
+ () => getMorphoEarn(client, network, address, market, markets.morphoMarketsData[market.value]),
300
+ (data) => { if (data && positive(data.amount)) stakingPositions[lower(address)].morphoBlue[market.value] = { error: '', data }; },
301
+ (err) => { stakingPositions[lower(address)].morphoBlue[market.value] = err; },
302
+ )) : []),
303
+ ...perAddress(morphoMidnightMarkets, (market, address) => {
304
+ if (!markets.morphoMidnightMarketsData[market.value]?.isCreated) return Promise.resolve();
305
+ return run(
306
+ `MorphoMidnight account data for address ${address} on market ${market.value}`,
307
+ () => _getMorphoMidnightAccountData(client, network, address, market, markets.morphoMidnightMarketsData[market.value]),
308
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].morphoMidnight[market.value] = { error: '', data }; },
309
+ (err) => { positions[lower(address)].morphoMidnight[market.value] = err; },
310
+ );
311
+ }),
312
+ ...perAddress(compoundV3Markets, (market, address) => run(
313
+ `CompoundV3 account data for address ${address} on market ${market.value}`,
314
+ () => _getCompoundV3AccountData(client, network, address, ZERO_ADDRESS, { selectedMarket: market, assetsData: markets.compoundV3MarketsData[market.value].assetsData }),
315
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].compoundV3[market.value] = { error: '', data }; },
316
+ (err) => { positions[lower(address)].compoundV3[market.value] = err; },
317
+ )),
318
+ ...perAddress(compoundV2Markets, (market, address) => run(
319
+ `CompoundV2 account data for address ${address}`,
320
+ () => _getCompoundV2AccountData(client, network, address, markets.compoundV2MarketsData[market.value].assetsData),
321
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].compoundV2[market.value] = { error: '', data }; },
322
+ (err) => { positions[lower(address)].compoundV2[market.value] = err; },
323
+ )),
324
+ ...perAddress(aaveV2Markets, (market, address) => run(
325
+ `AaveV2 account data for address ${address}`,
326
+ () => _getAaveV2AccountData(client, network, address, markets.aaveV2MarketsData[market.value].assetsData, market),
327
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].aaveV2[market.value] = { error: '', data }; },
328
+ (err) => { positions[lower(address)].aaveV2[market.value] = err; },
329
+ )),
330
+ ...perAddress(crvUsdMarkets, (market, address) => run(
331
+ `Curve USD account data for address ${address} on market ${market.value}`,
332
+ () => _getCurveUsdUserData(client, network, address, market, markets.crvUsdMarketsData[market.value].activeBand, markets.crvUsdMarketsData[market.value].borrowRate),
333
+ (data) => { if (positive(data.suppliedUsd) || positive(data.borrowedUsd)) positions[lower(address)].crvUsd[market.value] = { error: '', data }; },
334
+ (err) => { positions[lower(address)].crvUsd[market.value] = err; },
335
+ )),
336
+ ...perAddress(llamaLendMarkets, (market, address) => run(
337
+ `LlamaLend account data for address ${address} on market ${market.value}`,
338
+ () => _getLlamaLendUserData(client, network, address, market, markets.llamaLendMarketsData[market.value]),
339
+ (data) => {
340
+ if (positive(data.suppliedUsd) || positive(data.borrowedUsd)) {
341
+ positions[lower(address)].llamaLend[market.value] = { error: '', data: { ...data, borrowRate: markets.llamaLendMarketsData[market.value].borrowRate } };
342
+ }
343
+ },
344
+ (err) => { positions[lower(address)].llamaLend[market.value] = err; },
345
+ )),
346
+ ...addresses.map((address) => (makerCdps[lower(address)] || []).map((cdpInfo) => run(
347
+ `Maker CDP data for address ${address} with ID ${cdpInfo.id}`,
348
+ () => _getMakerCdpData(client, network, cdpInfo, markets.makerMarketsData[cdpInfo.ilkLabel]),
349
+ (data) => { if (data) positions[lower(address)].maker[cdpInfo.id] = { error: '', data }; },
350
+ (err) => { positions[lower(address)].maker[cdpInfo.id] = err; },
351
+ ))).flat(),
352
+ ...addresses.map((address) => fetchLiquity && run(
353
+ `Liquity trove info for address ${address}`,
354
+ () => _getLiquityTroveInfo(client, network, address),
355
+ (data) => { if (positive(data.collateral)) positions[lower(address)].liquity = { error: '', data }; },
356
+ (err) => { positions[lower(address)].liquity = err; },
357
+ )),
358
+ ...(fetchStaking && has(PortfolioProtocol.LiquityV2) ? addresses.map((address) => {
359
+ if (!isMainnet) {
360
+ stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data: null };
361
+ return Promise.resolve();
362
+ }
363
+ return run(
364
+ `sBold/yBold data for address ${address}`,
365
+ () => getLiquitySAndYBold(client, network, stakingPositions[lower(address)].liquityV2, address),
366
+ (data) => { stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data }; },
367
+ (err) => { stakingPositions[lower(address)].liquityV2SBoldYBold = err; },
368
+ );
369
+ }) : []),
370
+ ]);
371
+
372
+ return {
373
+ positions,
374
+ stakingPositions,
375
+ rewardsData,
376
+ markets,
377
+ };
378
+ }