@defisaver/positions-sdk 2.1.168 → 2.1.169-custom-fetching-2-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.
Files changed (42) hide show
  1. package/cjs/helpers/aaveV4Helpers/index.js +11 -1
  2. package/cjs/markets/morphoBlue/index.d.ts +2 -0
  3. package/cjs/markets/morphoBlue/index.js +18 -1
  4. package/cjs/moneymarket/moneymarketCommonService.js +12 -2
  5. package/cjs/portfolio/customDeFiData.d.ts +3 -0
  6. package/cjs/portfolio/customDeFiData.js +263 -0
  7. package/cjs/portfolio/index.d.ts +1 -0
  8. package/cjs/portfolio/index.js +15 -851
  9. package/cjs/services/viem.d.ts +2 -0
  10. package/cjs/services/viem.js +27 -1
  11. package/cjs/types/common.d.ts +1 -0
  12. package/cjs/types/common.js +1 -0
  13. package/cjs/types/morphoBlue.d.ts +1 -0
  14. package/cjs/types/morphoBlue.js +1 -0
  15. package/cjs/types/portfolio.d.ts +36 -0
  16. package/cjs/types/portfolio.js +18 -0
  17. package/esm/helpers/aaveV4Helpers/index.js +11 -1
  18. package/esm/markets/morphoBlue/index.d.ts +2 -0
  19. package/esm/markets/morphoBlue/index.js +16 -0
  20. package/esm/moneymarket/moneymarketCommonService.js +12 -2
  21. package/esm/portfolio/customDeFiData.d.ts +3 -0
  22. package/esm/portfolio/customDeFiData.js +257 -0
  23. package/esm/portfolio/index.d.ts +1 -0
  24. package/esm/portfolio/index.js +16 -849
  25. package/esm/services/viem.d.ts +2 -0
  26. package/esm/services/viem.js +25 -0
  27. package/esm/types/common.d.ts +1 -0
  28. package/esm/types/common.js +1 -0
  29. package/esm/types/morphoBlue.d.ts +1 -0
  30. package/esm/types/morphoBlue.js +1 -0
  31. package/esm/types/portfolio.d.ts +36 -0
  32. package/esm/types/portfolio.js +17 -1
  33. package/package.json +2 -2
  34. package/src/helpers/aaveV4Helpers/index.ts +12 -1
  35. package/src/markets/morphoBlue/index.ts +16 -0
  36. package/src/moneymarket/moneymarketCommonService.ts +13 -2
  37. package/src/portfolio/customDeFiData.ts +379 -0
  38. package/src/portfolio/index.ts +16 -834
  39. package/src/services/viem.ts +14 -0
  40. package/src/types/common.ts +1 -0
  41. package/src/types/morphoBlue.ts +1 -0
  42. package/src/types/portfolio.ts +39 -0
@@ -0,0 +1,379 @@
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, pinProviderBlock } 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 pin = (p: EthereumProvider) => (options.blockNumber !== undefined ? pinProviderBlock(p, options.blockNumber) : p);
78
+ const client = getViemProvider(pin(provider), network, { batch: { multicall: { batchSize } } });
79
+ const defaultClient = getViemProvider(pin(defaultProvider), network, { batch: { multicall: { batchSize } } });
80
+
81
+ const aaveV3Markets = has(PortfolioProtocol.AaveV3)
82
+ ? [AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi].map((v) => AaveMarkets(network)[v]).filter((m) => m.chainIds.includes(network))
83
+ : [];
84
+ const aaveV2Markets = has(PortfolioProtocol.AaveV2) ? [AaveMarkets(network)[AaveVersions.AaveV2]].filter((m) => m.chainIds.includes(network)) : [];
85
+ const aaveV4Spokes = has(PortfolioProtocol.AaveV4) ? supported(AaveV4Spokes(network), network) : [];
86
+ const compoundV3Markets = has(PortfolioProtocol.CompoundV3) ? supported(CompoundMarkets(network), network).filter((m) => m.value !== CompoundVersions.CompoundV2) : [];
87
+ const compoundV2Markets = has(PortfolioProtocol.CompoundV2) ? [CompoundMarkets(network)[CompoundVersions.CompoundV2]].filter((m) => m.chainIds.includes(network)) : [];
88
+ const sparkMarkets = has(PortfolioProtocol.Spark) ? supported(SparkMarkets(network), network) : [];
89
+ const morphoMarkets = has(PortfolioProtocol.MorphoBlue) ? supported(MorphoBlueMarkets(network), network) : [];
90
+ const morphoMidnightMarkets = has(PortfolioProtocol.MorphoMidnight) ? supported(MorphoMidnightMarkets(network), network) : [];
91
+ const crvUsdMarkets = has(PortfolioProtocol.CrvUsd) ? supported(CrvUsdMarkets(network), network) : [];
92
+ const llamaLendMarkets = has(PortfolioProtocol.LlamaLend) && [NetworkNumber.Eth, NetworkNumber.Arb].includes(network) ? supported(LlamaLendMarkets(network), network) : [];
93
+ const liquityV2Markets = has(PortfolioProtocol.LiquityV2) && isMainnet ? Object.values(LiquityV2Markets(network)) : [];
94
+ const liquityV2StakingMarkets = liquityV2Markets.filter((m) => !m.isLegacy);
95
+ const fetchMaker = has(PortfolioProtocol.Maker) && isMainnet;
96
+ const fetchLiquity = has(PortfolioProtocol.Liquity) && isMainnet;
97
+ const fetchFluid = has(PortfolioProtocol.Fluid) && isFluidSupported;
98
+
99
+ const markets: PortfolioMarketsData = {
100
+ morphoMarketsData: {},
101
+ morphoMidnightMarketsData: {},
102
+ compoundV3MarketsData: {},
103
+ sparkMarketsData: {},
104
+ aaveV3MarketsData: {},
105
+ aaveV2MarketsData: {},
106
+ compoundV2MarketsData: {},
107
+ crvUsdMarketsData: {},
108
+ llamaLendMarketsData: {},
109
+ liquityV2MarketsData: {},
110
+ aaveV4SpokesData: {},
111
+ fluidMarketsData: {},
112
+ makerMarketsData: {},
113
+ };
114
+ const makerCdps: Record<string, CdpInfo[]> = {};
115
+ const positions: PortfolioPositionsData = {};
116
+ const stakingPositions: Record<string, any> = {};
117
+ const rewardsData: Record<string, any> = {};
118
+
119
+ for (const address of addresses) {
120
+ positions[lower(address)] = {
121
+ aaveV3: {},
122
+ aaveV4: {},
123
+ morphoBlue: {},
124
+ morphoMidnight: {},
125
+ compoundV3: {},
126
+ spark: {},
127
+ maker: {},
128
+ aaveV2: {},
129
+ compoundV2: {},
130
+ liquity: {},
131
+ crvUsd: {},
132
+ llamaLend: {},
133
+ fluid: { error: '', data: {} },
134
+ };
135
+ if (fetchStaking) {
136
+ stakingPositions[lower(address)] = {
137
+ aaveV3: {}, morphoBlue: {}, liquity: {}, liquityV2: {}, fluid: { error: '', data: {} },
138
+ };
139
+ }
140
+ if (fetchRewards) {
141
+ rewardsData[lower(address)] = {
142
+ merkl: {}, aaveV3: {}, spark: {}, spk: {}, king: {}, ethena: {}, uniswap: {},
143
+ };
144
+ }
145
+ }
146
+
147
+ const run = async <T>(label: string, fetch: () => Promise<T>, store: (data: T) => void, onError: (err: { error: string, data: null }) => void) => {
148
+ try {
149
+ store(await fetch());
150
+ } catch (error) {
151
+ console.error(`Error fetching ${label}:`, error);
152
+ onError({ error: `Error fetching ${label}`, data: null });
153
+ }
154
+ };
155
+
156
+ const perAddress = <M>(list: M[], task: (market: M, address: EthAddress) => Promise<void>) => list.map((m) => addresses.map((a) => task(m, a))).flat();
157
+
158
+ const batchRewards = (key: string, label: string, fetch: () => Promise<Record<string, any>>, enabled = true) => (async () => {
159
+ if (!enabled) {
160
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: '', data: [] };
161
+ return;
162
+ }
163
+ try {
164
+ const result = await fetch();
165
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: '', data: result[lower(address)] || [] };
166
+ } catch (error) {
167
+ console.error(`Error fetching ${label}:`, error);
168
+ for (const address of addresses) rewardsData[lower(address)][key] = { error: `Error fetching ${label}`, data: null };
169
+ }
170
+ })();
171
+
172
+ await Promise.allSettled([
173
+ ...morphoMarkets.map(async (m) => { markets.morphoMarketsData[m.value] = await _getMorphoBluePortfolioMarketData(client, network, m); }),
174
+ ...morphoMidnightMarkets.map(async (m) => { markets.morphoMidnightMarketsData[m.value] = await _getMorphoMidnightMarketData(client, network, m); }),
175
+ ...compoundV3Markets.map(async (m) => { markets.compoundV3MarketsData[m.value] = await _getCompoundV3MarketsData(client, network, m, defaultClient); }),
176
+ ...sparkMarkets.map(async (m) => { markets.sparkMarketsData[m.value] = await _getSparkMarketsData(client, network, m); }),
177
+ ...aaveV3Markets.map(async (m) => { markets.aaveV3MarketsData[m.value] = await _getAaveV3MarketData(client, network, m); }),
178
+ ...aaveV4Spokes.map(async (s) => { markets.aaveV4SpokesData[s.value] = await _getAaveV4SpokeData(client, network, s); }),
179
+ ...aaveV2Markets.map(async (m) => { markets.aaveV2MarketsData[m.value] = await _getAaveV2MarketsData(client, network, m); }),
180
+ ...compoundV2Markets.map(async (m) => { markets.compoundV2MarketsData[m.value] = await _getCompoundV2MarketsData(client, network); }),
181
+ ...crvUsdMarkets.map(async (m) => { markets.crvUsdMarketsData[m.value] = await _getCurveUsdGlobalData(client, network, m); }),
182
+ ...llamaLendMarkets.map(async (m) => { markets.llamaLendMarketsData[m.value] = await _getLlamaLendGlobalData(client, network, m); }),
183
+ ...liquityV2Markets.map(async (m) => { markets.liquityV2MarketsData[m.value] = await _getLiquityV2MarketData(client, network, m); }),
184
+ (async () => {
185
+ if (!fetchFluid || !fetchFluidMarkets) return;
186
+ try { markets.fluidMarketsData = await _getAllFluidMarketDataPortfolio(client, network); } catch (error) { console.error('Error fetching Fluid markets data:', error); }
187
+ })(),
188
+ (async () => {
189
+ if (!fetchMaker) return;
190
+ try { markets.makerMarketsData = await _getMakerIlksData(client, network, MakerActiveIlks); } catch (error) { console.error('Error fetching Maker ilks data:', error); }
191
+ })(),
192
+
193
+ ...addresses.map(async (address) => {
194
+ if (!fetchMaker) return;
195
+ makerCdps[lower(address)] = await _getUserCdps(client, network, address);
196
+ }),
197
+ ...addresses.map((address) => fetchFluid && run(
198
+ `Fluid positions for address ${address}`,
199
+ () => _getUserPositionsPortfolio(client, network, address),
200
+ (userPositions) => {
201
+ for (const position of userPositions) {
202
+ if (position.userData && positive(position.userData.suppliedUsd)) positions[lower(address)].fluid.data[position.userData.nftId] = position.userData;
203
+ }
204
+ },
205
+ (err) => { positions[lower(address)].fluid = { error: err.error, data: {} }; },
206
+ )),
207
+
208
+ ...(fetchStaking ? [
209
+ ...addresses.map((address) => fetchFluid && run(
210
+ `Fluid lend data for address ${address}`,
211
+ () => _getAllUserEarnPositionsWithFTokens(client, network, address),
212
+ (data) => { stakingPositions[lower(address)].fluid = data; },
213
+ (err) => { stakingPositions[lower(address)].fluid = err; },
214
+ )),
215
+ ...addresses.map((address) => fetchLiquity && run(
216
+ `Liquity staking data for address ${address}`,
217
+ () => getLiquityStakingData(client, network, address),
218
+ (data) => { stakingPositions[lower(address)].liquity = data; },
219
+ (err) => { stakingPositions[lower(address)].liquity = err; },
220
+ )),
221
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(
222
+ `Aave V3 staking data for address ${address}`,
223
+ () => getStakeAaveData(client, network, address),
224
+ (data) => { stakingPositions[lower(address)].aaveV3 = data; },
225
+ (err) => { stakingPositions[lower(address)].aaveV3 = err; },
226
+ )),
227
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(
228
+ `Umbrella staking data for address ${address}`,
229
+ () => getUmbrellaData(client, network, address),
230
+ (data) => { stakingPositions[lower(address)].umbrella = data; },
231
+ (err) => { stakingPositions[lower(address)].umbrella = err; },
232
+ )),
233
+ ...perAddress(liquityV2StakingMarkets, (market, address) => run(
234
+ `Liquity V2 staking data for address ${address}, market ${market.value}`,
235
+ () => getLiquityV2Staking(client, network, market.value, address),
236
+ (data) => { stakingPositions[lower(address)].liquityV2[market.value] = { error: '', data }; },
237
+ (err) => { stakingPositions[lower(address)].liquityV2[market.value] = err; },
238
+ )),
239
+ ] : []),
240
+
241
+ ...(fetchRewards ? [
242
+ batchRewards('king', 'King rewards data', () => getKingRewards(client, network, addresses), isMainnet),
243
+ batchRewards('uniswap', 'Uniswap rewards data', () => getUniswapRewards(client, network, addresses), isMainnet),
244
+ batchRewards('spk', 'Spark Airdrop rewards data', () => fetchSparkAirdropRewards(client, network, addresses), isMainnet && has(PortfolioProtocol.Spark)),
245
+ batchRewards('ethena', 'Ethena Airdrop rewards data', () => fetchEthenaAirdropRewards(addresses), isMainnet),
246
+ ...addresses.map((address) => run(
247
+ `Merkl rewards data for address ${address}`,
248
+ () => getMerklUnclaimedRewards(address, network),
249
+ (data) => { rewardsData[lower(address)].merkl = { error: '', data }; },
250
+ (err) => { rewardsData[lower(address)].merkl = err; },
251
+ )),
252
+ ...perAddress(aaveV3Markets, (market, address) => run(
253
+ `Aave V3 rewards data for address ${address}, market ${market.value}`,
254
+ () => getUnclaimedRewardsForAllMarkets(client, network, address, market.providerAddress),
255
+ (data) => { rewardsData[lower(address)].aaveV3[market.value] = { error: '', data }; },
256
+ (err) => { rewardsData[lower(address)].aaveV3[market.value] = err; },
257
+ )),
258
+ ...perAddress(sparkMarkets, (market, address) => {
259
+ if (!isMainnet) {
260
+ rewardsData[lower(address)].spark[market.value] = { error: '', data: [] };
261
+ return Promise.resolve();
262
+ }
263
+ return run(
264
+ `Spark rewards data for address ${address}, market ${market.value}`,
265
+ () => fetchSparkRewards(client, network, address, market.providerAddress),
266
+ (data) => { rewardsData[lower(address)].spark[market.value] = { error: '', data }; },
267
+ (err) => { rewardsData[lower(address)].spark[market.value] = err; },
268
+ );
269
+ }),
270
+ ] : []),
271
+ ]);
272
+
273
+ await Promise.all([
274
+ ...perAddress(aaveV3Markets, (market, address) => run(
275
+ `AaveV3 account data for address ${address} on market ${market.value}`,
276
+ () => _getAaveV3AccountData(client, network, address, { selectedMarket: market, ...markets.aaveV3MarketsData[market.value] }),
277
+ (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd)) positions[lower(address)].aaveV3[market.value] = { error: '', data }; },
278
+ (err) => { positions[lower(address)].aaveV3[market.value] = err; },
279
+ )),
280
+ ...perAddress(sparkMarkets, (market, address) => run(
281
+ `Spark account data for address ${address} on market ${market.value}`,
282
+ () => _getSparkAccountData(client, network, address, { selectedMarket: market, assetsData: markets.sparkMarketsData[market.value].assetsData, eModeCategoriesData: markets.sparkMarketsData[market.value].eModeCategoriesData }),
283
+ (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd)) positions[lower(address)].spark[market.value] = { error: '', data }; },
284
+ (err) => { positions[lower(address)].spark[market.value] = err; },
285
+ )),
286
+ ...perAddress(aaveV4Spokes, (spoke, address) => run(
287
+ `AaveV4 account data for address ${address} on spoke ${spoke.value}`,
288
+ () => _getAaveV4AccountData(client, network, markets.aaveV4SpokesData[spoke.value], address),
289
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].aaveV4[spoke.value] = { error: '', data }; },
290
+ (err) => { positions[lower(address)].aaveV4[spoke.value] = err; },
291
+ )),
292
+ ...perAddress(morphoMarkets, (market, address) => run(
293
+ `MorphoBlue account data for address ${address} on market ${market.value}`,
294
+ () => _getMorphoBlueAccountData(client, network, address, market, markets.morphoMarketsData[market.value]),
295
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].morphoBlue[market.value] = { error: '', data }; },
296
+ (err) => { positions[lower(address)].morphoBlue[market.value] = err; },
297
+ )),
298
+ ...(fetchStaking ? perAddress(morphoMarkets, (market, address) => run(
299
+ `MorphoBlue earn data for address ${address} on market ${market.value}`,
300
+ () => getMorphoEarn(client, network, address, market, markets.morphoMarketsData[market.value]),
301
+ (data) => { if (data && positive(data.amount)) stakingPositions[lower(address)].morphoBlue[market.value] = { error: '', data }; },
302
+ (err) => { stakingPositions[lower(address)].morphoBlue[market.value] = err; },
303
+ )) : []),
304
+ ...perAddress(morphoMidnightMarkets, (market, address) => {
305
+ if (!markets.morphoMidnightMarketsData[market.value]?.isCreated) return Promise.resolve();
306
+ return run(
307
+ `MorphoMidnight account data for address ${address} on market ${market.value}`,
308
+ () => _getMorphoMidnightAccountData(client, network, address, market, markets.morphoMidnightMarketsData[market.value]),
309
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].morphoMidnight[market.value] = { error: '', data }; },
310
+ (err) => { positions[lower(address)].morphoMidnight[market.value] = err; },
311
+ );
312
+ }),
313
+ ...perAddress(compoundV3Markets, (market, address) => run(
314
+ `CompoundV3 account data for address ${address} on market ${market.value}`,
315
+ () => _getCompoundV3AccountData(client, network, address, ZERO_ADDRESS, { selectedMarket: market, assetsData: markets.compoundV3MarketsData[market.value].assetsData }),
316
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].compoundV3[market.value] = { error: '', data }; },
317
+ (err) => { positions[lower(address)].compoundV3[market.value] = err; },
318
+ )),
319
+ ...perAddress(compoundV2Markets, (market, address) => run(
320
+ `CompoundV2 account data for address ${address}`,
321
+ () => _getCompoundV2AccountData(client, network, address, markets.compoundV2MarketsData[market.value].assetsData),
322
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].compoundV2[market.value] = { error: '', data }; },
323
+ (err) => { positions[lower(address)].compoundV2[market.value] = err; },
324
+ )),
325
+ ...perAddress(aaveV2Markets, (market, address) => run(
326
+ `AaveV2 account data for address ${address}`,
327
+ () => _getAaveV2AccountData(client, network, address, markets.aaveV2MarketsData[market.value].assetsData, market),
328
+ (data) => { if (positive(data.suppliedUsd)) positions[lower(address)].aaveV2[market.value] = { error: '', data }; },
329
+ (err) => { positions[lower(address)].aaveV2[market.value] = err; },
330
+ )),
331
+ ...perAddress(crvUsdMarkets, (market, address) => run(
332
+ `Curve USD account data for address ${address} on market ${market.value}`,
333
+ () => _getCurveUsdUserData(client, network, address, market, markets.crvUsdMarketsData[market.value].activeBand, markets.crvUsdMarketsData[market.value].borrowRate),
334
+ (data) => { if (positive(data.suppliedUsd) || positive(data.borrowedUsd)) positions[lower(address)].crvUsd[market.value] = { error: '', data }; },
335
+ (err) => { positions[lower(address)].crvUsd[market.value] = err; },
336
+ )),
337
+ ...perAddress(llamaLendMarkets, (market, address) => run(
338
+ `LlamaLend account data for address ${address} on market ${market.value}`,
339
+ () => _getLlamaLendUserData(client, network, address, market, markets.llamaLendMarketsData[market.value]),
340
+ (data) => {
341
+ if (positive(data.suppliedUsd) || positive(data.borrowedUsd)) {
342
+ positions[lower(address)].llamaLend[market.value] = { error: '', data: { ...data, borrowRate: markets.llamaLendMarketsData[market.value].borrowRate } };
343
+ }
344
+ },
345
+ (err) => { positions[lower(address)].llamaLend[market.value] = err; },
346
+ )),
347
+ ...addresses.map((address) => (makerCdps[lower(address)] || []).map((cdpInfo) => run(
348
+ `Maker CDP data for address ${address} with ID ${cdpInfo.id}`,
349
+ () => _getMakerCdpData(client, network, cdpInfo, markets.makerMarketsData[cdpInfo.ilkLabel]),
350
+ (data) => { if (data) positions[lower(address)].maker[cdpInfo.id] = { error: '', data }; },
351
+ (err) => { positions[lower(address)].maker[cdpInfo.id] = err; },
352
+ ))).flat(),
353
+ ...addresses.map((address) => fetchLiquity && run(
354
+ `Liquity trove info for address ${address}`,
355
+ () => _getLiquityTroveInfo(client, network, address),
356
+ (data) => { if (positive(data.collateral)) positions[lower(address)].liquity = { error: '', data }; },
357
+ (err) => { positions[lower(address)].liquity = err; },
358
+ )),
359
+ ...(fetchStaking && has(PortfolioProtocol.LiquityV2) ? addresses.map((address) => {
360
+ if (!isMainnet) {
361
+ stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data: null };
362
+ return Promise.resolve();
363
+ }
364
+ return run(
365
+ `sBold/yBold data for address ${address}`,
366
+ () => getLiquitySAndYBold(client, network, stakingPositions[lower(address)].liquityV2, address),
367
+ (data) => { stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data }; },
368
+ (err) => { stakingPositions[lower(address)].liquityV2SBoldYBold = err; },
369
+ );
370
+ }) : []),
371
+ ]);
372
+
373
+ return {
374
+ positions,
375
+ stakingPositions,
376
+ rewardsData,
377
+ markets,
378
+ };
379
+ }