@defisaver/positions-sdk 2.1.161-portfolio-api-2-dev → 2.1.162-npm-token-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.
- package/cjs/aaveV3/index.d.ts +12 -2
- package/cjs/aaveV3/index.js +7 -1
- package/cjs/aaveV3/sgho.d.ts +16 -2
- package/cjs/claiming/aaveV3.d.ts +2 -2
- package/cjs/claiming/ethena.d.ts +1 -2
- package/cjs/claiming/king.d.ts +1 -2
- package/cjs/claiming/spark.d.ts +2 -2
- package/cjs/fluid/index.d.ts +49 -5
- package/cjs/helpers/aaveHelpers/index.d.ts +9 -1
- package/cjs/helpers/aaveHelpers/index.js +23 -6
- package/cjs/liquity/index.d.ts +12 -2
- package/cjs/liquityV2/index.d.ts +23 -3
- package/cjs/portfolio/index.d.ts +5 -5
- package/cjs/portfolio/index.js +36 -51
- package/cjs/savings/index.js +5 -2
- package/cjs/savings/morphoVaults/index.d.ts +1 -1
- package/cjs/savings/morphoVaults/index.js +56 -18
- package/cjs/savings/morphoVaults/options.d.ts +2 -0
- package/cjs/savings/morphoVaults/options.js +61 -1
- package/cjs/spark/index.js +1 -0
- package/cjs/types/aave.d.ts +3 -98
- package/cjs/types/compound.d.ts +2 -26
- package/cjs/types/curveUsd.d.ts +1 -9
- package/cjs/types/fluid.d.ts +0 -13
- package/cjs/types/index.d.ts +0 -1
- package/cjs/types/index.js +0 -1
- package/cjs/types/liquity.d.ts +0 -12
- package/cjs/types/liquityV2.d.ts +0 -24
- package/cjs/types/llamaLend.d.ts +1 -12
- package/cjs/types/morphoBlue.d.ts +0 -2
- package/cjs/types/portfolio.d.ts +10 -88
- package/cjs/types/savings/morphoVaults.d.ts +10 -2
- package/cjs/types/savings/morphoVaults.js +9 -1
- package/cjs/types/spark.d.ts +1 -21
- package/cjs/umbrella/index.d.ts +3 -2
- package/esm/aaveV3/index.d.ts +12 -2
- package/esm/aaveV3/index.js +7 -1
- package/esm/aaveV3/sgho.d.ts +16 -2
- package/esm/claiming/aaveV3.d.ts +2 -2
- package/esm/claiming/aaveV3.js +1 -1
- package/esm/claiming/ethena.d.ts +1 -2
- package/esm/claiming/king.d.ts +1 -2
- package/esm/claiming/spark.d.ts +2 -2
- package/esm/claiming/spark.js +1 -1
- package/esm/fluid/index.d.ts +49 -5
- package/esm/helpers/aaveHelpers/index.d.ts +9 -1
- package/esm/helpers/aaveHelpers/index.js +20 -5
- package/esm/liquity/index.d.ts +12 -2
- package/esm/liquityV2/index.d.ts +23 -3
- package/esm/portfolio/index.d.ts +5 -5
- package/esm/portfolio/index.js +36 -51
- package/esm/savings/index.js +5 -2
- package/esm/savings/morphoVaults/index.d.ts +1 -1
- package/esm/savings/morphoVaults/index.js +57 -19
- package/esm/savings/morphoVaults/options.d.ts +2 -0
- package/esm/savings/morphoVaults/options.js +61 -1
- package/esm/spark/index.js +1 -0
- package/esm/types/aave.d.ts +3 -98
- package/esm/types/compound.d.ts +2 -26
- package/esm/types/curveUsd.d.ts +1 -9
- package/esm/types/fluid.d.ts +0 -13
- package/esm/types/index.d.ts +0 -1
- package/esm/types/index.js +0 -1
- package/esm/types/liquity.d.ts +0 -12
- package/esm/types/liquityV2.d.ts +0 -24
- package/esm/types/llamaLend.d.ts +1 -12
- package/esm/types/morphoBlue.d.ts +0 -2
- package/esm/types/portfolio.d.ts +10 -88
- package/esm/types/savings/morphoVaults.d.ts +10 -2
- package/esm/types/savings/morphoVaults.js +8 -0
- package/esm/types/spark.d.ts +1 -21
- package/esm/umbrella/index.d.ts +3 -2
- package/package.json +3 -2
- package/src/aaveV3/index.ts +7 -3
- package/src/aaveV3/sgho.ts +17 -2
- package/src/claiming/aaveV3.ts +2 -4
- package/src/claiming/ethena.ts +5 -5
- package/src/claiming/king.ts +3 -3
- package/src/claiming/spark.ts +4 -6
- package/src/fluid/index.ts +3 -4
- package/src/helpers/aaveHelpers/index.ts +24 -7
- package/src/liquity/index.ts +2 -2
- package/src/liquityV2/index.ts +3 -3
- package/src/portfolio/index.ts +57 -76
- package/src/savings/index.ts +5 -2
- package/src/savings/morphoVaults/index.ts +73 -21
- package/src/savings/morphoVaults/options.ts +67 -1
- package/src/spark/index.ts +1 -0
- package/src/types/aave.ts +2 -104
- package/src/types/compound.ts +2 -38
- package/src/types/curveUsd.ts +1 -17
- package/src/types/fluid.ts +0 -14
- package/src/types/index.ts +1 -2
- package/src/types/liquity.ts +1 -13
- package/src/types/liquityV2.ts +1 -26
- package/src/types/llamaLend.ts +1 -19
- package/src/types/morphoBlue.ts +0 -3
- package/src/types/portfolio.ts +11 -111
- package/src/types/savings/morphoVaults.ts +11 -1
- package/src/types/spark.ts +1 -25
- package/src/umbrella/index.ts +1 -2
package/src/portfolio/index.ts
CHANGED
|
@@ -27,11 +27,7 @@ import {
|
|
|
27
27
|
LlamaLendGlobalMarketData,
|
|
28
28
|
MorphoBlueMarketInfo,
|
|
29
29
|
MorphoMidnightMarketInfo,
|
|
30
|
-
PortfolioDataOptions,
|
|
31
|
-
PortfolioMarketsData,
|
|
32
30
|
PortfolioPositionsData,
|
|
33
|
-
PortfolioRewardsData,
|
|
34
|
-
PortfolioStakingPositionsData,
|
|
35
31
|
SparkMarketsData,
|
|
36
32
|
} from '../types';
|
|
37
33
|
import { _getCompoundV3AccountData, _getCompoundV3MarketsData } from '../compoundV3';
|
|
@@ -55,18 +51,13 @@ import { fetchEthenaAirdropRewards } from '../claiming/ethena';
|
|
|
55
51
|
import { _getAaveV4AccountData, _getAaveV4SpokeData } from '../aaveV4';
|
|
56
52
|
import { getUniswapRewards } from '../claiming/uniswap';
|
|
57
53
|
|
|
58
|
-
export async function getPortfolioData(provider: EthereumProvider, network: NetworkNumber, defaultProvider: EthereumProvider, addresses: EthAddress[], isSim = false
|
|
54
|
+
export async function getPortfolioData(provider: EthereumProvider, network: NetworkNumber, defaultProvider: EthereumProvider, addresses: EthAddress[], isSim = false): Promise<{
|
|
59
55
|
positions: PortfolioPositionsData;
|
|
60
|
-
stakingPositions:
|
|
61
|
-
rewardsData:
|
|
62
|
-
markets:
|
|
56
|
+
stakingPositions: any;
|
|
57
|
+
rewardsData: any;
|
|
58
|
+
markets: any;
|
|
63
59
|
}> {
|
|
64
60
|
const isMainnet = network === NetworkNumber.Eth;
|
|
65
|
-
const includeStaking = options.staking !== false;
|
|
66
|
-
const includeRewards = options.rewards !== false;
|
|
67
|
-
// The addresses staking and rewards are read for: none when left out, so their fetches below make no calls.
|
|
68
|
-
const stakingAddresses = includeStaking ? addresses : [];
|
|
69
|
-
const rewardsAddresses = includeRewards ? addresses : [];
|
|
70
61
|
const isFluidSupported = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Base, NetworkNumber.Plasma].includes(network);
|
|
71
62
|
|
|
72
63
|
const morphoMarkets = Object.values(MorphoBlueMarkets(network)).filter((market) => market.chainIds.includes(network));
|
|
@@ -105,7 +96,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
105
96
|
const liquityV2MarketsData: Record<string, LiquityV2MarketData> = {};
|
|
106
97
|
const aaveV4SpokesData: Record<string, AaveV4SpokeData> = {};
|
|
107
98
|
|
|
108
|
-
const markets
|
|
99
|
+
const markets = {
|
|
109
100
|
morphoMarketsData,
|
|
110
101
|
morphoMidnightMarketsData,
|
|
111
102
|
compoundV3MarketsData,
|
|
@@ -120,8 +111,8 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
120
111
|
};
|
|
121
112
|
|
|
122
113
|
const positions: PortfolioPositionsData = {};
|
|
123
|
-
const stakingPositions:
|
|
124
|
-
const rewardsData:
|
|
114
|
+
const stakingPositions: any = {};
|
|
115
|
+
const rewardsData: any = {};
|
|
125
116
|
const allAddresses = [...addresses];
|
|
126
117
|
|
|
127
118
|
for (const address of allAddresses) {
|
|
@@ -146,7 +137,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
146
137
|
}
|
|
147
138
|
|
|
148
139
|
// TODO: check default values, probably needed when fetching portfolio on unsupported networks
|
|
149
|
-
for (const address of
|
|
140
|
+
for (const address of addresses) {
|
|
150
141
|
stakingPositions[address.toLowerCase() as EthAddress] = {
|
|
151
142
|
aaveV3: {},
|
|
152
143
|
morphoBlue: {},
|
|
@@ -160,21 +151,15 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
160
151
|
error: '',
|
|
161
152
|
data: {},
|
|
162
153
|
},
|
|
163
|
-
// Set by the sBOLD/yBOLD fetch below, whether it succeeds or fails.
|
|
164
|
-
liquityV2SBoldYBold: { error: '', data: null },
|
|
165
154
|
};
|
|
166
|
-
}
|
|
167
155
|
|
|
168
|
-
for (const address of rewardsAddresses) {
|
|
169
|
-
// merkl, spk, king and uniswap are set by their fetches below, whether they succeed or fail.
|
|
170
156
|
rewardsData[address.toLowerCase() as EthAddress] = {
|
|
171
|
-
merkl: {
|
|
157
|
+
merkl: {},
|
|
172
158
|
aaveV3: {},
|
|
173
159
|
spark: {},
|
|
174
|
-
spk: {
|
|
175
|
-
king: {
|
|
160
|
+
spk: {},
|
|
161
|
+
king: {},
|
|
176
162
|
ethena: {},
|
|
177
|
-
uniswap: { error: '', data: null },
|
|
178
163
|
};
|
|
179
164
|
}
|
|
180
165
|
|
|
@@ -250,54 +235,54 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
250
235
|
}),
|
|
251
236
|
|
|
252
237
|
// === STAKING DATA (independent of market data) ===
|
|
253
|
-
...
|
|
238
|
+
...addresses.map(async (address) => {
|
|
254
239
|
try {
|
|
255
240
|
if (!isFluidSupported) return;
|
|
256
|
-
stakingPositions[address.toLowerCase()
|
|
241
|
+
stakingPositions[address.toLowerCase()].fluid = await _getAllUserEarnPositionsWithFTokens(client, network, address);
|
|
257
242
|
} catch (error) {
|
|
258
243
|
console.error(`Error fetching Fluid lend data for address ${address}:`, error);
|
|
259
|
-
stakingPositions[address.toLowerCase()
|
|
244
|
+
stakingPositions[address.toLowerCase()].fluid = { error: `Error fetching Fluid lend data for address ${address}`, data: null };
|
|
260
245
|
}
|
|
261
246
|
}),
|
|
262
|
-
...
|
|
247
|
+
...addresses.map(async (address) => {
|
|
263
248
|
try {
|
|
264
249
|
if (!isMainnet) return;
|
|
265
|
-
stakingPositions[address.toLowerCase()
|
|
250
|
+
stakingPositions[address.toLowerCase()].liquity = await getLiquityStakingData(client, network, address);
|
|
266
251
|
} catch (error) {
|
|
267
252
|
console.error(`Error fetching Liquity staking data for address ${address}:`, error);
|
|
268
|
-
stakingPositions[address.toLowerCase()
|
|
253
|
+
stakingPositions[address.toLowerCase()].liquity = { error: `Error fetching Liquity staking data for address ${address}`, data: null };
|
|
269
254
|
}
|
|
270
255
|
}),
|
|
271
|
-
...
|
|
256
|
+
...addresses.map(async (address) => {
|
|
272
257
|
try {
|
|
273
258
|
if (!isMainnet) return;
|
|
274
|
-
stakingPositions[address.toLowerCase()
|
|
259
|
+
stakingPositions[address.toLowerCase()].aaveV3 = await getStakeAaveData(client, network, address);
|
|
275
260
|
} catch (error) {
|
|
276
261
|
console.error(`Error fetching Aave V3 staking data for address ${address}:`, error);
|
|
277
|
-
stakingPositions[address.toLowerCase()
|
|
262
|
+
stakingPositions[address.toLowerCase()].aaveV3 = { error: `Error fetching Aave V3 staking data for address ${address}`, data: null };
|
|
278
263
|
}
|
|
279
264
|
}),
|
|
280
|
-
...
|
|
265
|
+
...addresses.map(async (address) => {
|
|
281
266
|
try {
|
|
282
267
|
if (!isMainnet) return;
|
|
283
|
-
stakingPositions[address.toLowerCase()
|
|
268
|
+
stakingPositions[address.toLowerCase()].umbrella = await getUmbrellaData(client, network, address);
|
|
284
269
|
} catch (error) {
|
|
285
270
|
console.error(`Error fetching Umbrella staking data for address ${address}:`, error);
|
|
286
|
-
stakingPositions[address.toLowerCase()
|
|
271
|
+
stakingPositions[address.toLowerCase()].umbrella = { error: `Error fetching Umbrella staking data for address ${address}`, data: null };
|
|
287
272
|
}
|
|
288
273
|
}),
|
|
289
274
|
// Liquity V2 staking
|
|
290
|
-
...liquityV2MarketsStaking.map(market =>
|
|
275
|
+
...liquityV2MarketsStaking.map(market => addresses.map(async (address) => {
|
|
291
276
|
try {
|
|
292
277
|
if (!isMainnet) {
|
|
293
|
-
stakingPositions[address.toLowerCase()
|
|
278
|
+
stakingPositions[address.toLowerCase()].liquityV2[market.value] = { error: '', data: null };
|
|
294
279
|
return;
|
|
295
280
|
}
|
|
296
281
|
const liquityV2StakingData = await getLiquityV2Staking(client, network, market.value, address);
|
|
297
|
-
stakingPositions[address.toLowerCase()
|
|
282
|
+
stakingPositions[address.toLowerCase()].liquityV2[market.value] = { error: '', data: liquityV2StakingData };
|
|
298
283
|
} catch (error) {
|
|
299
284
|
console.error(`Error fetching Liquity V2 staking data for address ${address}, market ${market.value}:`, error);
|
|
300
|
-
stakingPositions[address.toLowerCase()
|
|
285
|
+
stakingPositions[address.toLowerCase()].liquityV2[market.value] = { error: `Error fetching Liquity V2 staking data for address ${address}`, data: null };
|
|
301
286
|
}
|
|
302
287
|
})).flat(),
|
|
303
288
|
|
|
@@ -306,13 +291,13 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
306
291
|
(async () => {
|
|
307
292
|
try {
|
|
308
293
|
if (!isMainnet) {
|
|
309
|
-
for (const address of
|
|
310
|
-
rewardsData[address.toLowerCase()
|
|
294
|
+
for (const address of addresses) {
|
|
295
|
+
rewardsData[address.toLowerCase()].king = { error: '', data: [] };
|
|
311
296
|
}
|
|
312
297
|
return;
|
|
313
298
|
}
|
|
314
|
-
const kingRewards = await getKingRewards(client, network,
|
|
315
|
-
for (const address of
|
|
299
|
+
const kingRewards = await getKingRewards(client, network, addresses);
|
|
300
|
+
for (const address of addresses) {
|
|
316
301
|
const lowerAddress = address.toLowerCase() as EthAddress;
|
|
317
302
|
rewardsData[lowerAddress].king = {
|
|
318
303
|
error: '',
|
|
@@ -321,7 +306,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
321
306
|
}
|
|
322
307
|
} catch (error) {
|
|
323
308
|
console.error('Error fetching King rewards data in batch:', error);
|
|
324
|
-
for (const address of
|
|
309
|
+
for (const address of addresses) {
|
|
325
310
|
rewardsData[address.toLowerCase() as EthAddress].king = {
|
|
326
311
|
error: 'Error fetching King rewards data in batch',
|
|
327
312
|
data: null,
|
|
@@ -333,13 +318,13 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
333
318
|
(async () => {
|
|
334
319
|
try {
|
|
335
320
|
if (!isMainnet) {
|
|
336
|
-
for (const address of
|
|
337
|
-
rewardsData[address.toLowerCase()
|
|
321
|
+
for (const address of addresses) {
|
|
322
|
+
rewardsData[address.toLowerCase()].uniswap = { error: '', data: [] };
|
|
338
323
|
}
|
|
339
324
|
return;
|
|
340
325
|
}
|
|
341
|
-
const uniswapRewards = await getUniswapRewards(client, network,
|
|
342
|
-
for (const address of
|
|
326
|
+
const uniswapRewards = await getUniswapRewards(client, network, addresses);
|
|
327
|
+
for (const address of addresses) {
|
|
343
328
|
const lowerAddress = address.toLowerCase() as EthAddress;
|
|
344
329
|
rewardsData[lowerAddress].uniswap = {
|
|
345
330
|
error: '',
|
|
@@ -348,7 +333,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
348
333
|
}
|
|
349
334
|
} catch (error) {
|
|
350
335
|
console.error('Error fetching Uniswap rewards data in batch:', error);
|
|
351
|
-
for (const address of
|
|
336
|
+
for (const address of addresses) {
|
|
352
337
|
rewardsData[address.toLowerCase() as EthAddress].uniswap = {
|
|
353
338
|
error: 'Error fetching Uniswap rewards data in batch',
|
|
354
339
|
data: null,
|
|
@@ -356,10 +341,10 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
356
341
|
}
|
|
357
342
|
}
|
|
358
343
|
})(),
|
|
359
|
-
...sparkMarkets.map((market) =>
|
|
344
|
+
...sparkMarkets.map((market) => addresses.map(async address => {
|
|
360
345
|
try {
|
|
361
346
|
if (!isMainnet) {
|
|
362
|
-
rewardsData[address.toLowerCase()
|
|
347
|
+
rewardsData[address.toLowerCase()].spark[market.value] = { error: '', data: [] };
|
|
363
348
|
return;
|
|
364
349
|
}
|
|
365
350
|
const sparkData = await fetchSparkRewards(client, network, address, market.providerAddress);
|
|
@@ -369,7 +354,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
369
354
|
rewardsData[address.toLowerCase() as EthAddress].spark[market.value] = { error: `Error fetching Spark rewards data for address ${address}`, data: null };
|
|
370
355
|
}
|
|
371
356
|
})).flat(),
|
|
372
|
-
...
|
|
357
|
+
...addresses.map(async (address) => {
|
|
373
358
|
try {
|
|
374
359
|
const merklData = await getMerklUnclaimedRewards(address, network);
|
|
375
360
|
rewardsData[address.toLowerCase() as EthAddress].merkl = { error: '', data: merklData };
|
|
@@ -378,28 +363,27 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
378
363
|
rewardsData[address.toLowerCase() as EthAddress].merkl = { error: `Error fetching Merkl rewards data for address ${address}`, data: null };
|
|
379
364
|
}
|
|
380
365
|
}),
|
|
381
|
-
...aaveV3Markets.map(market =>
|
|
366
|
+
...aaveV3Markets.map(market => addresses.map(async (address) => {
|
|
382
367
|
try {
|
|
383
368
|
const aaveData = await getUnclaimedRewardsForAllMarkets(client, network, address, market.providerAddress);
|
|
384
369
|
rewardsData[address.toLowerCase() as EthAddress].aaveV3[market.value] = { error: '', data: aaveData };
|
|
385
370
|
} catch (error) {
|
|
386
371
|
console.error(`Error fetching Aave V3 Merit rewards data for address ${address}:`, error);
|
|
387
|
-
|
|
388
|
-
rewardsData[address.toLowerCase() as EthAddress].aaveV3[market.value] = { error: `Error fetching Aave V3 rewards data for address ${address} on market ${market.value}`, data: null };
|
|
372
|
+
rewardsData[address.toLowerCase() as EthAddress].aaveV3 = { error: `Error fetching Aave V3 rewards data for address ${address}`, data: null };
|
|
389
373
|
}
|
|
390
374
|
})).flat(),
|
|
391
375
|
// Batch Spark Airdrop rewards
|
|
392
376
|
(async () => {
|
|
393
377
|
try {
|
|
394
378
|
if (!isMainnet) {
|
|
395
|
-
for (const address of
|
|
396
|
-
rewardsData[address.toLowerCase()
|
|
379
|
+
for (const address of addresses) {
|
|
380
|
+
rewardsData[address.toLowerCase()].spk = { error: '', data: [] };
|
|
397
381
|
}
|
|
398
382
|
return;
|
|
399
383
|
}
|
|
400
384
|
|
|
401
|
-
const sparkAirdropRewards = await fetchSparkAirdropRewards(client, network,
|
|
402
|
-
for (const address of
|
|
385
|
+
const sparkAirdropRewards = await fetchSparkAirdropRewards(client, network, addresses);
|
|
386
|
+
for (const address of addresses) {
|
|
403
387
|
const lowerAddress = address.toLowerCase() as EthAddress;
|
|
404
388
|
rewardsData[lowerAddress].spk = {
|
|
405
389
|
error: '',
|
|
@@ -408,7 +392,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
408
392
|
}
|
|
409
393
|
} catch (error) {
|
|
410
394
|
console.error('Error fetching Spark Airdrop rewards data in batch:', error);
|
|
411
|
-
for (const address of
|
|
395
|
+
for (const address of addresses) {
|
|
412
396
|
rewardsData[address.toLowerCase() as EthAddress].spk = {
|
|
413
397
|
error: 'Error fetching Spark Airdrop rewards data in batch',
|
|
414
398
|
data: null,
|
|
@@ -422,8 +406,8 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
422
406
|
return;
|
|
423
407
|
}
|
|
424
408
|
|
|
425
|
-
const ethenaAirdropRewards = await fetchEthenaAirdropRewards(
|
|
426
|
-
for (const address of
|
|
409
|
+
const ethenaAirdropRewards = await fetchEthenaAirdropRewards(addresses);
|
|
410
|
+
for (const address of addresses) {
|
|
427
411
|
const lowerAddress = address.toLowerCase() as EthAddress;
|
|
428
412
|
rewardsData[lowerAddress].ethena = {
|
|
429
413
|
error: '',
|
|
@@ -432,7 +416,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
432
416
|
}
|
|
433
417
|
} catch (error) {
|
|
434
418
|
console.error('Error fetching Ethena Airdrop rewards data:', error);
|
|
435
|
-
for (const address of
|
|
419
|
+
for (const address of addresses) {
|
|
436
420
|
rewardsData[address.toLowerCase() as EthAddress].ethena = {
|
|
437
421
|
error: 'Error fetching Ethena Airdrop rewards data in batch',
|
|
438
422
|
data: null,
|
|
@@ -465,16 +449,15 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
465
449
|
try {
|
|
466
450
|
const [accDataPromise, earnDataPromise] = await Promise.allSettled([
|
|
467
451
|
_getMorphoBlueAccountData(client, network, address, market, morphoMarketsData[market.value]),
|
|
468
|
-
|
|
452
|
+
getMorphoEarn(client, network, address, market, morphoMarketsData[market.value]),
|
|
469
453
|
]);
|
|
470
454
|
if (accDataPromise.status === 'rejected') {
|
|
471
455
|
console.error(`Error fetching MorphoBlue account data for address ${address} on market ${market.value}:`, accDataPromise.reason);
|
|
472
456
|
positions[address.toLowerCase() as EthAddress].morphoBlue[market.value] = { error: `Error fetching MorphoBlue account data for address ${address} on market ${market.value}`, data: null };
|
|
473
457
|
}
|
|
474
458
|
if (earnDataPromise.status === 'rejected') {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
stakingPositions[address.toLowerCase() as EthAddress].morphoBlue[market.value] = { error: `Error fetching MorphoBlue earn data for address ${address} on market ${market.value}`, data: null };
|
|
459
|
+
console.error(`Error fetching MorphoBlue account data for address ${address} on market ${market.value}:`, earnDataPromise.reason);
|
|
460
|
+
positions[address.toLowerCase() as EthAddress].morphoBlue[market.value] = { error: `Error fetching MorphoBlue account data for address ${address} on market ${market.value}`, data: null };
|
|
478
461
|
}
|
|
479
462
|
if (accDataPromise.status !== 'rejected') {
|
|
480
463
|
const accData = accDataPromise.value;
|
|
@@ -523,9 +506,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
523
506
|
positions[address.toLowerCase() as EthAddress].spark[market.value] = { error: `Error fetching Spark account data for address ${address} on market ${market.value}`, data: null };
|
|
524
507
|
}
|
|
525
508
|
})).flat(),
|
|
526
|
-
|
|
527
|
-
// before a vault's data lands and the vault is missing from the result.
|
|
528
|
-
...addresses.flatMap((address) => (makerCdps[address.toLowerCase() as EthAddress] ?? []).map(async (cdpInfo) => {
|
|
509
|
+
...addresses.map(async (address) => makerCdps[address.toLowerCase() as EthAddress]?.map(async (cdpInfo) => {
|
|
529
510
|
try {
|
|
530
511
|
const cdpData = await _getMakerCdpData(client, network, cdpInfo);
|
|
531
512
|
if (cdpData) {
|
|
@@ -535,7 +516,7 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
535
516
|
console.error(`Error fetching Maker CDP data for address ${address} with ID ${cdpInfo.id}:`, error);
|
|
536
517
|
positions[address.toLowerCase() as EthAddress].maker[cdpInfo.id] = { error: `Error fetching Maker CDP data for address ${address} with ID ${cdpInfo.id}`, data: null };
|
|
537
518
|
}
|
|
538
|
-
})),
|
|
519
|
+
})).flat(),
|
|
539
520
|
...aaveV2Markets.map((market) => addresses.map(async (address) => {
|
|
540
521
|
try {
|
|
541
522
|
const accData = await _getAaveV2AccountData(client, network, address, aaveV2MarketsData[market.value].assetsData, market);
|
|
@@ -587,13 +568,13 @@ export async function getPortfolioData(provider: EthereumProvider, network: Netw
|
|
|
587
568
|
}
|
|
588
569
|
})).flat(),
|
|
589
570
|
// liquity sBold/yBold and staking options
|
|
590
|
-
...
|
|
571
|
+
...addresses.map(async (address) => {
|
|
591
572
|
try {
|
|
592
573
|
if (!isMainnet) {
|
|
593
574
|
stakingPositions[address.toLowerCase() as EthAddress].liquityV2SBoldYBold = { error: '', data: null };
|
|
594
575
|
return;
|
|
595
576
|
}
|
|
596
|
-
const data = await getLiquitySAndYBold(client, network, stakingPositions[address.toLowerCase()
|
|
577
|
+
const data = await getLiquitySAndYBold(client, network, stakingPositions[address.toLowerCase()].liquityV2, address);
|
|
597
578
|
stakingPositions[address.toLowerCase() as EthAddress].liquityV2SBoldYBold = { error: '', data };
|
|
598
579
|
} catch (error) {
|
|
599
580
|
console.error(`Error fetching SBold/YBold data for address ${address}:`, error);
|
package/src/savings/index.ts
CHANGED
|
@@ -32,7 +32,8 @@ export const getSavingsData = async (
|
|
|
32
32
|
network: NetworkNumber,
|
|
33
33
|
accounts: EthAddress[],
|
|
34
34
|
) => {
|
|
35
|
-
const morphoVaultsList = Object.keys(morphoVaults.morphoVaultsOptions.MORPHO_VAULTS) as MorphoVaultType[]
|
|
35
|
+
const morphoVaultsList = (Object.keys(morphoVaults.morphoVaultsOptions.MORPHO_VAULTS) as MorphoVaultType[])
|
|
36
|
+
.filter((key) => morphoVaults.morphoVaultsOptions.getMorphoVault(key).network === network);
|
|
36
37
|
const yearnVaultsList = Object.keys(yearnVaults.yearnVaultsOptions.YEARN_VAULTS) as YearnVaultType[];
|
|
37
38
|
const sparkSavingsVaultsList = Object.keys(sparkSavingsVaults.sparkSavingsVaultsOptions.SPARK_SAVINGS_VAULTS) as SparkSavingsVaultType[];
|
|
38
39
|
const yearnV3VaultsList = Object.keys(yearnV3Vaults.yearnV3VaultsOptions.YEARN_V3_VAULTS) as YearnV3VaultType[];
|
|
@@ -42,7 +43,7 @@ export const getSavingsData = async (
|
|
|
42
43
|
const savingsData: SavingsData = {};
|
|
43
44
|
|
|
44
45
|
await Promise.all([
|
|
45
|
-
...(
|
|
46
|
+
...(morphoVaultsList.length ? [
|
|
46
47
|
(async () => {
|
|
47
48
|
try {
|
|
48
49
|
const vaults = morphoVaultsList.map((vaultKey) => morphoVaults.morphoVaultsOptions.getMorphoVault(vaultKey));
|
|
@@ -52,6 +53,8 @@ export const getSavingsData = async (
|
|
|
52
53
|
console.error('[getSavingsData] Error fetching morpho vaults:', err);
|
|
53
54
|
}
|
|
54
55
|
})(),
|
|
56
|
+
] : []),
|
|
57
|
+
...(network === NetworkNumber.Eth ? [
|
|
55
58
|
...yearnVaultsList.map(async (vaultKey) => {
|
|
56
59
|
try {
|
|
57
60
|
const vault = yearnVaults.yearnVaultsOptions.getYearnVault(vaultKey);
|
|
@@ -4,10 +4,10 @@ import { request as graphqlRequest } from 'graphql-request';
|
|
|
4
4
|
import { assetAmountInEth } from '@defisaver/tokens';
|
|
5
5
|
import * as morphoVaultsOptions from './options';
|
|
6
6
|
import {
|
|
7
|
-
EthAddress, EthereumProvider, NetworkNumber, MorphoVault, MorphoVaultType, SavingsVaultData,
|
|
7
|
+
EthAddress, EthereumProvider, NetworkNumber, MorphoVault, MorphoVaultType, MorphoVaultVersion, SavingsVaultData,
|
|
8
8
|
} from '../../types';
|
|
9
9
|
import { getViemProvider } from '../../services/viem';
|
|
10
|
-
import { getMorphoVaultContractViem } from '../../contracts';
|
|
10
|
+
import { getErc4626ContractViem, getMorphoVaultContractViem } from '../../contracts';
|
|
11
11
|
import { MORPHO_API_URL } from '../../constants';
|
|
12
12
|
|
|
13
13
|
export {
|
|
@@ -17,38 +17,49 @@ export {
|
|
|
17
17
|
// Morpho API caps list page size at 100 items
|
|
18
18
|
const MORPHO_API_PAGE_SIZE = 100;
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const buildLiquidityQuery = (listField: 'vaults' | 'vaultV2s') => `
|
|
21
21
|
query VaultsLiquidity($addresses: [String!], $chainIds: [Int!]) {
|
|
22
|
-
|
|
22
|
+
${listField}(first: ${MORPHO_API_PAGE_SIZE}, where: { address_in: $addresses, chainId_in: $chainIds }) {
|
|
23
23
|
items {
|
|
24
24
|
address
|
|
25
|
-
liquidity {
|
|
26
|
-
underlying
|
|
27
|
-
}
|
|
25
|
+
liquidity${listField === 'vaults' ? ' {\n underlying\n }' : ''}
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
}`;
|
|
31
29
|
|
|
30
|
+
const liquidityQueries = {
|
|
31
|
+
[MorphoVaultVersion.V1]: { field: 'vaults', query: buildLiquidityQuery('vaults') },
|
|
32
|
+
[MorphoVaultVersion.V2]: { field: 'vaultV2s', query: buildLiquidityQuery('vaultV2s') },
|
|
33
|
+
} as const;
|
|
34
|
+
|
|
35
|
+
type LiquidityItem = { address: string, liquidity: { underlying: string | number | null } | string | number | null };
|
|
36
|
+
|
|
32
37
|
/**
|
|
33
|
-
* Fetches liquidity for all given vaults
|
|
38
|
+
* Fetches liquidity for all given vaults, one API request per vault version (chunked if over the page cap),
|
|
34
39
|
* returned as a map keyed by lowercased vault address. A vault missing from the API response is
|
|
35
40
|
* absent from the map.
|
|
36
41
|
*/
|
|
37
42
|
export const fetchMorphoVaultsLiquidity = async (network: NetworkNumber, vaults: MorphoVault[]): Promise<Record<string, string>> => {
|
|
38
|
-
const
|
|
39
|
-
|
|
43
|
+
const requests: { version: MorphoVaultVersion, chunk: MorphoVault[] }[] = [];
|
|
44
|
+
[MorphoVaultVersion.V1, MorphoVaultVersion.V2].forEach((version) => {
|
|
45
|
+
const versionVaults = vaults.filter((vault) => vault.version === version);
|
|
46
|
+
for (let i = 0; i < versionVaults.length; i += MORPHO_API_PAGE_SIZE) requests.push({ version, chunk: versionVaults.slice(i, i + MORPHO_API_PAGE_SIZE) });
|
|
47
|
+
});
|
|
40
48
|
|
|
41
49
|
const liquidityByAddress: Record<string, string> = {};
|
|
42
|
-
await Promise.all(
|
|
43
|
-
const
|
|
50
|
+
await Promise.all(requests.map(async ({ version, chunk }) => {
|
|
51
|
+
const { field, query } = liquidityQueries[version];
|
|
52
|
+
const data = await graphqlRequest(MORPHO_API_URL, query, {
|
|
44
53
|
addresses: chunk.map((vault) => vault.address),
|
|
45
54
|
chainIds: [network],
|
|
46
55
|
// the BigInt scalar serializes as a JSON number when it fits in Number.MAX_SAFE_INTEGER, a string otherwise
|
|
47
|
-
}) as
|
|
56
|
+
}) as Record<string, { items: LiquidityItem[] | null }>;
|
|
48
57
|
|
|
49
|
-
(data.
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
(data[field].items || []).forEach((item) => {
|
|
59
|
+
// V1 exposes liquidity as { underlying }, V2 as a plain BigInt scalar
|
|
60
|
+
const underlying = item?.liquidity !== null && typeof item?.liquidity === 'object' ? item.liquidity.underlying : item?.liquidity;
|
|
61
|
+
if (underlying !== undefined && underlying !== null) {
|
|
62
|
+
liquidityByAddress[item.address.toLowerCase()] = String(underlying);
|
|
52
63
|
}
|
|
53
64
|
});
|
|
54
65
|
}));
|
|
@@ -63,7 +74,22 @@ const getBatchedViemProvider = (provider: EthereumProvider, network: NetworkNumb
|
|
|
63
74
|
},
|
|
64
75
|
});
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
// Vault V2 is ERC-4626 but has no decimals offset, so shares are converted with convertToAssets
|
|
78
|
+
const getMorphoVaultV2ChainData = async (provider: Client, morphoVault: MorphoVault, accounts: EthAddress[]) => {
|
|
79
|
+
const vaultContract = getErc4626ContractViem(provider, morphoVault.address);
|
|
80
|
+
|
|
81
|
+
const [totalAssets, suppliedAssets] = await Promise.all([
|
|
82
|
+
vaultContract.read.totalAssets(),
|
|
83
|
+
Promise.all(accounts.map(async (account) => {
|
|
84
|
+
const share = await vaultContract.read.balanceOf([account]);
|
|
85
|
+
return share === BigInt(0) ? BigInt(0) : vaultContract.read.convertToAssets([share]);
|
|
86
|
+
})),
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
return { totalAssets, suppliedAssets };
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const getMorphoVaultV1ChainData = async (provider: Client, morphoVault: MorphoVault, accounts: EthAddress[]) => {
|
|
67
93
|
const morphoVaultContract = getMorphoVaultContractViem(provider, morphoVault.address);
|
|
68
94
|
|
|
69
95
|
const shares: Record<EthAddress, bigint> = {};
|
|
@@ -84,20 +110,46 @@ const getMorphoVaultChainData = async (provider: Client, morphoVault: MorphoVaul
|
|
|
84
110
|
};
|
|
85
111
|
};
|
|
86
112
|
|
|
113
|
+
type MorphoVaultChainData = {
|
|
114
|
+
v1?: Awaited<ReturnType<typeof getMorphoVaultV1ChainData>>,
|
|
115
|
+
v2?: Awaited<ReturnType<typeof getMorphoVaultV2ChainData>>,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const getMorphoVaultChainData = async (provider: Client, morphoVault: MorphoVault, accounts: EthAddress[]): Promise<MorphoVaultChainData> => (
|
|
119
|
+
morphoVault.version === MorphoVaultVersion.V2
|
|
120
|
+
? { v2: await getMorphoVaultV2ChainData(provider, morphoVault, accounts) }
|
|
121
|
+
: { v1: await getMorphoVaultV1ChainData(provider, morphoVault, accounts) }
|
|
122
|
+
);
|
|
123
|
+
|
|
87
124
|
const formatMorphoVaultData = (
|
|
88
125
|
morphoVault: MorphoVault,
|
|
89
|
-
chainData:
|
|
126
|
+
chainData: MorphoVaultChainData,
|
|
90
127
|
liquidityUnderlying: string,
|
|
91
128
|
accounts: EthAddress[],
|
|
92
129
|
): SavingsVaultData => {
|
|
130
|
+
const liquidity = assetAmountInEth(liquidityUnderlying, morphoVault.asset);
|
|
131
|
+
const supplied: Record<EthAddress, string> = {};
|
|
132
|
+
|
|
133
|
+
if (chainData.v2) {
|
|
134
|
+
const { totalAssets, suppliedAssets } = chainData.v2;
|
|
135
|
+
accounts.forEach((account, i) => {
|
|
136
|
+
supplied[account.toLowerCase() as EthAddress] = assetAmountInEth(suppliedAssets[i].toString(), morphoVault.asset);
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
poolSize: assetAmountInEth(totalAssets.toString(), morphoVault.asset),
|
|
140
|
+
supplied,
|
|
141
|
+
liquidity,
|
|
142
|
+
asset: morphoVault.asset,
|
|
143
|
+
optionType: morphoVault.type,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
93
147
|
const {
|
|
94
148
|
totalAssets, totalSupply, decimals, decimalsOffset, shares,
|
|
95
|
-
} = chainData
|
|
149
|
+
} = chainData.v1!;
|
|
96
150
|
|
|
97
151
|
const poolSize = assetAmountInEth(totalAssets.toString(), morphoVault.asset);
|
|
98
|
-
const liquidity = assetAmountInEth(liquidityUnderlying, morphoVault.asset);
|
|
99
152
|
|
|
100
|
-
const supplied: Record<EthAddress, string> = {};
|
|
101
153
|
accounts.forEach((account) => {
|
|
102
154
|
const share = shares[account] || BigInt(0);
|
|
103
155
|
supplied[account.toLowerCase() as EthAddress] = new Dec(new Dec(share.toString()).mul(new Dec(totalAssets.toString()).add(1)).div(new Dec(totalSupply.toString()).add(10 ** decimalsOffset)).div(10 ** 18)
|