@tokemak/queries 0.0.9 → 0.0.11
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/dist/index.cjs +2339 -993
- package/dist/index.d.ts +26 -1994
- package/dist/index.js +2116 -840
- package/dist/index.rn-bd847515.d.ts +1979 -0
- package/dist/index.rn.cjs +2076 -0
- package/dist/index.rn.d.ts +7 -0
- package/dist/index.rn.js +2063 -0
- package/package.json +10 -10
package/dist/index.rn.js
ADDED
|
@@ -0,0 +1,2063 @@
|
|
|
1
|
+
import { sepolia, mainnet, sonic, base } from 'viem/chains';
|
|
2
|
+
import { TOKEMAK_SWAP_PRICING_URL, SUPPORTED_DEV_CHAINS, SUPPORTED_PROD_CHAINS, TOKEMAK_GENSTRAT_APRS_API_URL } from '@tokemak/constants';
|
|
3
|
+
import { ETH_TOKEN, PXETH_TOKEN, USDC_TOKEN, DOLA_TOKEN, S_TOKEN, EURC_TOKEN, USDT_TOKEN, USDT0_TOKEN, TOKE_TOKEN, SILO_TOKEN, XPL_TOKEN, WXPL_TOKEN, WETH_TOKEN, WS_TOKEN, BEETS_PROTOCOL, ALL_TOKENS, ALL_AUTOPOOLS } from '@tokemak/tokenlist';
|
|
4
|
+
import { formatEtherNum, formatUnitsNum, convertTimestampToDate, formatDateToReadable, getToken, formatPoolName, getProtocol, getNetwork } from '@tokemak/utils';
|
|
5
|
+
import { getAddress, hexToBigInt, formatUnits, erc20Abi } from 'viem';
|
|
6
|
+
import { getSdkByChainId } from '@tokemak/graph-cli';
|
|
7
|
+
import { AUTOPOOLS_WHITELIST_PROD, getMainnetConfig, getCoreConfig } from '@tokemak/config';
|
|
8
|
+
import { readContract, readContracts } from '@wagmi/core';
|
|
9
|
+
import { stakingV1Abi, rewardsV1Abi, accTokeV1Abi, autopoolEthAbi, rewardsV1HashAbi, systemRegistryAbi, lensAbi } from '@tokemak/abis';
|
|
10
|
+
|
|
11
|
+
// functions/getEthPrice.ts
|
|
12
|
+
|
|
13
|
+
// functions/getDefillamaPrice.ts
|
|
14
|
+
var getDefillamaPrice = async (tokenAddress) => {
|
|
15
|
+
const response = await fetch(
|
|
16
|
+
`https://coins.llama.fi/prices/current/ethereum:${tokenAddress}`
|
|
17
|
+
);
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
return data.coins[`ethereum:${tokenAddress}`].price;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// functions/getTokenPrice.ts
|
|
23
|
+
var getTokenPrice = async ({
|
|
24
|
+
chainId = 1,
|
|
25
|
+
tokenAddress,
|
|
26
|
+
includedSources,
|
|
27
|
+
excludedSources
|
|
28
|
+
}) => {
|
|
29
|
+
try {
|
|
30
|
+
const params = new URLSearchParams({
|
|
31
|
+
chainId: chainId.toString(),
|
|
32
|
+
systemName: "gen3",
|
|
33
|
+
token: tokenAddress
|
|
34
|
+
});
|
|
35
|
+
if (includedSources) {
|
|
36
|
+
params.set("includedSources", includedSources.join(","));
|
|
37
|
+
}
|
|
38
|
+
if (excludedSources) {
|
|
39
|
+
params.set("excludedSources", excludedSources.join(","));
|
|
40
|
+
}
|
|
41
|
+
const response = await fetch(`${TOKEMAK_SWAP_PRICING_URL}?${params}`);
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
return data.price;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
try {
|
|
46
|
+
const defillamaPrice = await getDefillamaPrice(tokenAddress);
|
|
47
|
+
return defillamaPrice;
|
|
48
|
+
} catch (error2) {
|
|
49
|
+
console.log(error2);
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// functions/getTokenPriceFallback.ts
|
|
56
|
+
async function getTokenPriceFallback(tokenSymbol) {
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch(
|
|
59
|
+
"https://tokemakmarketdata.s3.amazonaws.com/current.json"
|
|
60
|
+
);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
console.error(
|
|
63
|
+
`Request failed with status: ${response.status} - ${response.statusText}. Returning fallback.`
|
|
64
|
+
);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const data = await response.json();
|
|
68
|
+
if (!data.prices || !(tokenSymbol in data.prices)) {
|
|
69
|
+
console.warn(
|
|
70
|
+
`Token symbol "${tokenSymbol}" not found in price data. Returning fallback.`
|
|
71
|
+
);
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
return data.prices[tokenSymbol];
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`Error fetching or parsing price data:`, error);
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// functions/getEthPrice.ts
|
|
82
|
+
var getEthPrice = async () => {
|
|
83
|
+
try {
|
|
84
|
+
return await getTokenPrice({
|
|
85
|
+
chainId: sepolia.id,
|
|
86
|
+
tokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.warn("Primary price fetch failed. Attempting fallback...", error);
|
|
90
|
+
try {
|
|
91
|
+
const fallbackPrice = await getTokenPriceFallback("eth");
|
|
92
|
+
return fallbackPrice;
|
|
93
|
+
} catch (fallbackError) {
|
|
94
|
+
console.error("Fallback fetch also failed:", fallbackError);
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var getTokePrice = async () => {
|
|
100
|
+
try {
|
|
101
|
+
return await getTokenPrice({ tokenAddress: TOKE_TOKEN.address });
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.warn("Primary price fetch failed. Attempting fallback...", error);
|
|
104
|
+
try {
|
|
105
|
+
const fallbackPrice = await getTokenPriceFallback("toke");
|
|
106
|
+
return fallbackPrice;
|
|
107
|
+
} catch (fallbackError) {
|
|
108
|
+
console.error("Fallback fetch also failed:", fallbackError);
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// utils/fillMissingDates.ts
|
|
115
|
+
function fillMissingDates(data) {
|
|
116
|
+
data.sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
117
|
+
let filledData = [];
|
|
118
|
+
let currentDate;
|
|
119
|
+
const today = /* @__PURE__ */ new Date();
|
|
120
|
+
data.forEach((entry, index) => {
|
|
121
|
+
currentDate = new Date(entry.date);
|
|
122
|
+
filledData.push(entry);
|
|
123
|
+
let nextDay = new Date(currentDate);
|
|
124
|
+
nextDay.setDate(nextDay.getDate() + 1);
|
|
125
|
+
let nextEntry = data[index + 1];
|
|
126
|
+
while (nextEntry && nextDay < nextEntry.date) {
|
|
127
|
+
let newTimestamp = Math.floor(nextDay.getTime() / 1e3).toString();
|
|
128
|
+
let newEntry = {
|
|
129
|
+
...entry,
|
|
130
|
+
date: new Date(nextDay),
|
|
131
|
+
timestamp: newTimestamp
|
|
132
|
+
};
|
|
133
|
+
filledData.push(newEntry);
|
|
134
|
+
nextDay.setDate(nextDay.getDate() + 1);
|
|
135
|
+
}
|
|
136
|
+
if (!nextEntry) {
|
|
137
|
+
while (nextDay <= today) {
|
|
138
|
+
let newTimestamp = Math.floor(nextDay.getTime() / 1e3).toString();
|
|
139
|
+
let newEntry = {
|
|
140
|
+
...entry,
|
|
141
|
+
date: new Date(nextDay),
|
|
142
|
+
timestamp: newTimestamp
|
|
143
|
+
};
|
|
144
|
+
filledData.push(newEntry);
|
|
145
|
+
nextDay.setDate(nextDay.getDate() + 1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return filledData;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// utils/mergeArraysWithKey.ts
|
|
153
|
+
function mergeArraysWithKey(objectsArray, arraysArray, key) {
|
|
154
|
+
if (objectsArray.length !== arraysArray.length) {
|
|
155
|
+
throw new Error("Both arrays must have the same length.");
|
|
156
|
+
}
|
|
157
|
+
return objectsArray.map((obj, index) => ({
|
|
158
|
+
...obj,
|
|
159
|
+
[key]: arraysArray[index]
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// utils/mergeArrays.ts
|
|
164
|
+
function mergeArrays(objectsArray, objectsToMergeArray) {
|
|
165
|
+
if (objectsArray.length !== objectsToMergeArray.length) {
|
|
166
|
+
throw new Error("Both arrays must have the same length.");
|
|
167
|
+
}
|
|
168
|
+
return objectsArray.map((obj, index) => ({
|
|
169
|
+
...obj,
|
|
170
|
+
...objectsToMergeArray[index]
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
function getChainsForEnv({
|
|
174
|
+
includeTestnet = false
|
|
175
|
+
}) {
|
|
176
|
+
let chains;
|
|
177
|
+
chains = includeTestnet ? [...SUPPORTED_DEV_CHAINS] : [...SUPPORTED_PROD_CHAINS];
|
|
178
|
+
return chains;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// utils/getAutopoolCategory.ts
|
|
182
|
+
var ETH_BASE_ASSETS = ["ETH", "WETH"];
|
|
183
|
+
var USD_BASE_ASSETS = ["USDC", "DOLA", "USDT0"];
|
|
184
|
+
var EUR_BASE_ASSETS = ["EURC"];
|
|
185
|
+
var getAutopoolCategory = (baseAsset) => {
|
|
186
|
+
if (ETH_BASE_ASSETS.includes(baseAsset?.toUpperCase())) {
|
|
187
|
+
return "eth" /* ETH */;
|
|
188
|
+
} else if (USD_BASE_ASSETS.includes(baseAsset?.toUpperCase()) || EUR_BASE_ASSETS.includes(baseAsset?.toUpperCase())) {
|
|
189
|
+
return "stables" /* STABLES */;
|
|
190
|
+
}
|
|
191
|
+
return "crypto" /* CRYPTO */;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// utils/convertBaseAssetToTokenPrices.ts
|
|
195
|
+
var convertBaseAssetToTokenPrices = (baseAssetValue, baseAssetPrice, prices) => {
|
|
196
|
+
const baseAssetToTokenPrices = Object.fromEntries(
|
|
197
|
+
Object.entries(prices).map(([tokenSymbol, tokenPrice]) => [
|
|
198
|
+
tokenSymbol,
|
|
199
|
+
baseAssetPrice / tokenPrice
|
|
200
|
+
])
|
|
201
|
+
);
|
|
202
|
+
return {
|
|
203
|
+
baseAsset: baseAssetValue,
|
|
204
|
+
USD: baseAssetValue * baseAssetPrice,
|
|
205
|
+
...Object.fromEntries(
|
|
206
|
+
Object.entries(baseAssetToTokenPrices).map(([tokenSymbol, price]) => [
|
|
207
|
+
tokenSymbol.toUpperCase(),
|
|
208
|
+
baseAssetValue * price
|
|
209
|
+
])
|
|
210
|
+
)
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// utils/convertBaseAssetToTokenPricesAndDenom.ts
|
|
215
|
+
var convertBaseAssetToTokenPricesAndDenom = (baseAsset, baseAssetPrice, denomPrice, prices) => {
|
|
216
|
+
const baseAssetToDenom = baseAssetPrice / denomPrice;
|
|
217
|
+
return {
|
|
218
|
+
...convertBaseAssetToTokenPrices(baseAsset, baseAssetPrice, prices),
|
|
219
|
+
denom: baseAsset * baseAssetToDenom
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
var getAutopoolInfo = (symbol) => {
|
|
223
|
+
const autopool = ALL_AUTOPOOLS.find((pool) => pool.symbol === symbol);
|
|
224
|
+
return autopool;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// utils/findClosestEntry.ts
|
|
228
|
+
function findClosestEntry(data, targetValue, propertyKey, maxDifference = Infinity, getValue) {
|
|
229
|
+
if (!data || data.length === 0)
|
|
230
|
+
return null;
|
|
231
|
+
let closestEntry = null;
|
|
232
|
+
let minDiff = Infinity;
|
|
233
|
+
for (const entry of data) {
|
|
234
|
+
const value = getValue ? getValue(entry) : entry[propertyKey];
|
|
235
|
+
if (typeof value !== "number" || isNaN(value))
|
|
236
|
+
continue;
|
|
237
|
+
const diff = Math.abs(value - targetValue);
|
|
238
|
+
if (diff < minDiff && diff <= maxDifference) {
|
|
239
|
+
minDiff = diff;
|
|
240
|
+
closestEntry = entry;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return closestEntry;
|
|
244
|
+
}
|
|
245
|
+
function findClosestTimestampEntry(data, targetTimestamp, maxDifferenceInSeconds = 3600 * 12) {
|
|
246
|
+
return findClosestEntry(
|
|
247
|
+
data,
|
|
248
|
+
targetTimestamp,
|
|
249
|
+
"timestamp",
|
|
250
|
+
maxDifferenceInSeconds
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function findClosestDateEntry(data, targetDate, maxDifferenceInMs = 24 * 60 * 60 * 1e3) {
|
|
254
|
+
return findClosestEntry(
|
|
255
|
+
data,
|
|
256
|
+
targetDate.getTime(),
|
|
257
|
+
"date",
|
|
258
|
+
maxDifferenceInMs,
|
|
259
|
+
(item) => item.date.getTime()
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// functions/getBlobData.ts
|
|
264
|
+
var getBlobData = async (blobName) => {
|
|
265
|
+
try {
|
|
266
|
+
const blobUrl = `https://kg4e5p7eknl8rdgg.public.blob.vercel-storage.com/${blobName}`;
|
|
267
|
+
const response = await fetch(blobUrl, { cache: "no-store" });
|
|
268
|
+
if (!response.ok) {
|
|
269
|
+
console.warn(
|
|
270
|
+
`Failed to fetch blob data for ${blobName}: ${response.status} ${response.statusText}`
|
|
271
|
+
);
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const data = await response.text();
|
|
275
|
+
return JSON.parse(data);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.warn(`Failed to fetch blob data for ${blobName}:`, error);
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// functions/getPoolsAndDestinationsBackup.ts
|
|
283
|
+
var getPoolsAndDestinationsBackup = async (chainId) => {
|
|
284
|
+
try {
|
|
285
|
+
const networkName = getNetwork(chainId)?.name.toLowerCase();
|
|
286
|
+
const backupData = await getBlobData(
|
|
287
|
+
`${networkName}-getPoolsAndDestinations-latest-success.json`
|
|
288
|
+
);
|
|
289
|
+
return backupData?.data;
|
|
290
|
+
} catch (e) {
|
|
291
|
+
console.error(e);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// constants/tokenOrders.ts
|
|
296
|
+
var UITokenOrder = [
|
|
297
|
+
"ETH",
|
|
298
|
+
"WETH",
|
|
299
|
+
"STETH",
|
|
300
|
+
"WSTETH",
|
|
301
|
+
"RETH",
|
|
302
|
+
"SWETH",
|
|
303
|
+
"FRXETH",
|
|
304
|
+
"SFRXETH",
|
|
305
|
+
"EETH",
|
|
306
|
+
"CBETH",
|
|
307
|
+
"OSETH",
|
|
308
|
+
"PXETH",
|
|
309
|
+
"OETH",
|
|
310
|
+
"EZETH",
|
|
311
|
+
"RSETH",
|
|
312
|
+
"RSWETH",
|
|
313
|
+
"ETHX",
|
|
314
|
+
"RSWETH",
|
|
315
|
+
"PUFETH",
|
|
316
|
+
"USDC",
|
|
317
|
+
"DOLA",
|
|
318
|
+
"USDT",
|
|
319
|
+
"DAI"
|
|
320
|
+
];
|
|
321
|
+
var protocolOrder = [
|
|
322
|
+
"Balancer",
|
|
323
|
+
"Curve",
|
|
324
|
+
"Aerodrome",
|
|
325
|
+
"Pendle",
|
|
326
|
+
"Aave",
|
|
327
|
+
"Morpho",
|
|
328
|
+
"Fluid"
|
|
329
|
+
];
|
|
330
|
+
var getGenStratAprs = async ({
|
|
331
|
+
chainId = 1
|
|
332
|
+
}) => {
|
|
333
|
+
try {
|
|
334
|
+
const params = new URLSearchParams({
|
|
335
|
+
chainId: chainId.toString(),
|
|
336
|
+
systemName: "gen3"
|
|
337
|
+
});
|
|
338
|
+
const response = await fetch(`${TOKEMAK_GENSTRAT_APRS_API_URL}?${params}`);
|
|
339
|
+
const data = await response.json();
|
|
340
|
+
if (data && data.success) {
|
|
341
|
+
return data.aprs.reduce((p, c) => {
|
|
342
|
+
if (!p[c.autopoolAddress]) {
|
|
343
|
+
p[c.autopoolAddress] = {};
|
|
344
|
+
}
|
|
345
|
+
for (const d of c.destinations) {
|
|
346
|
+
p[c.autopoolAddress][d.address] = {
|
|
347
|
+
name: d.name,
|
|
348
|
+
apr: d.apr
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return p;
|
|
352
|
+
}, {});
|
|
353
|
+
} else {
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.log(error);
|
|
358
|
+
return void 0;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
var getPoolsAndDestinations = async (wagmiConfig, { chainId }) => {
|
|
362
|
+
try {
|
|
363
|
+
const { lens } = getCoreConfig(chainId);
|
|
364
|
+
const { autoPools, destinations } = await readContract(wagmiConfig, {
|
|
365
|
+
address: lens,
|
|
366
|
+
abi: lensAbi,
|
|
367
|
+
functionName: "getPoolsAndDestinations",
|
|
368
|
+
chainId
|
|
369
|
+
});
|
|
370
|
+
const autopoolsAndDestinations = mergeArraysWithKey(
|
|
371
|
+
autoPools,
|
|
372
|
+
destinations,
|
|
373
|
+
"destinations"
|
|
374
|
+
);
|
|
375
|
+
return autopoolsAndDestinations;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
console.error(`Error on ${chainId} in getPoolsAndDestinations:`, error);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
var getBackupApr = async (chainId, poolAddress) => {
|
|
381
|
+
try {
|
|
382
|
+
const networkName = getNetwork(chainId)?.name.toLowerCase();
|
|
383
|
+
const backupData = await getBlobData(
|
|
384
|
+
`${networkName}-getChainAutopools-latest-success.json`
|
|
385
|
+
);
|
|
386
|
+
if (backupData) {
|
|
387
|
+
const backupApr = backupData.data.find(
|
|
388
|
+
(item) => item.poolAddress.toLowerCase() === poolAddress.toLowerCase()
|
|
389
|
+
)?.apr.base;
|
|
390
|
+
return backupApr || 0;
|
|
391
|
+
}
|
|
392
|
+
} catch (e) {
|
|
393
|
+
console.error(e);
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// functions/getChainAutopools.ts
|
|
400
|
+
var getChainAutopools = async (wagmiConfig, {
|
|
401
|
+
chainId,
|
|
402
|
+
prices
|
|
403
|
+
}) => {
|
|
404
|
+
const { GetVaultAddeds, GetAutopoolsInactiveDestinations } = getSdkByChainId(chainId);
|
|
405
|
+
try {
|
|
406
|
+
const { vaultAddeds } = await GetVaultAddeds();
|
|
407
|
+
const { GetAutopoolsApr } = getSdkByChainId(chainId);
|
|
408
|
+
const { autopools: autopoolsApr } = await GetAutopoolsApr();
|
|
409
|
+
const genStratAprs = await getGenStratAprs({
|
|
410
|
+
chainId
|
|
411
|
+
});
|
|
412
|
+
let autopoolsAndDestinations = await getPoolsAndDestinations(wagmiConfig, {
|
|
413
|
+
chainId
|
|
414
|
+
});
|
|
415
|
+
if (!autopoolsAndDestinations) {
|
|
416
|
+
const backupData = await getPoolsAndDestinationsBackup(chainId);
|
|
417
|
+
if (backupData) {
|
|
418
|
+
autopoolsAndDestinations = backupData;
|
|
419
|
+
} else {
|
|
420
|
+
throw new Error(`No autopools and destinations found for ${chainId}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const vaultAddedMapping = vaultAddeds.reduce((acc, vaultAdded) => {
|
|
424
|
+
acc[vaultAdded.vault.toLowerCase()] = Number(vaultAdded.blockTimestamp);
|
|
425
|
+
return acc;
|
|
426
|
+
}, {});
|
|
427
|
+
const autopools = await Promise.all(
|
|
428
|
+
autopoolsAndDestinations.map(async (autopool) => {
|
|
429
|
+
let baseAsset = getToken(autopool.baseAsset);
|
|
430
|
+
if (!baseAsset?.symbol) {
|
|
431
|
+
console.error(
|
|
432
|
+
"FIX THIS BEFORE PROD: base asset not found",
|
|
433
|
+
autopool.baseAsset
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
let baseAssetPrice = prices[(baseAsset?.symbol || "").toUpperCase()];
|
|
437
|
+
if (!baseAssetPrice) {
|
|
438
|
+
baseAssetPrice = await getTokenPrice({
|
|
439
|
+
chainId: baseAsset.chainId,
|
|
440
|
+
tokenAddress: baseAsset.address
|
|
441
|
+
}) || 0;
|
|
442
|
+
}
|
|
443
|
+
const timestamp = vaultAddedMapping[autopool.poolAddress.toLowerCase()];
|
|
444
|
+
const totalAssets = formatUnitsNum(
|
|
445
|
+
autopool.totalAssets,
|
|
446
|
+
baseAsset.decimals
|
|
447
|
+
);
|
|
448
|
+
const tvl = totalAssets * baseAssetPrice;
|
|
449
|
+
const totalIdleAssets = formatUnitsNum(
|
|
450
|
+
autopool.totalIdle,
|
|
451
|
+
baseAsset.decimals
|
|
452
|
+
);
|
|
453
|
+
const exchangeValues = {};
|
|
454
|
+
const destinations = autopool.destinations.map((destination) => {
|
|
455
|
+
const debtValueHeldByVaultEth = formatUnitsNum(
|
|
456
|
+
destination.debtValueHeldByVault,
|
|
457
|
+
baseAsset.decimals
|
|
458
|
+
);
|
|
459
|
+
if (!exchangeValues[destination.exchangeName.toLowerCase()]) {
|
|
460
|
+
exchangeValues[destination.exchangeName.toLowerCase()] = 0;
|
|
461
|
+
}
|
|
462
|
+
exchangeValues[destination.exchangeName.toLowerCase()] += debtValueHeldByVaultEth;
|
|
463
|
+
const tokensWithValue = mergeArrays(
|
|
464
|
+
destination.underlyingTokens,
|
|
465
|
+
destination.underlyingTokenValueHeld
|
|
466
|
+
);
|
|
467
|
+
let underlyingTokens = tokensWithValue.map((token) => {
|
|
468
|
+
const tokenDetails = getToken(token.tokenAddress);
|
|
469
|
+
let value = formatUnitsNum(
|
|
470
|
+
token.valueHeldInEth,
|
|
471
|
+
baseAsset.decimals
|
|
472
|
+
);
|
|
473
|
+
let valueUsd = value * baseAssetPrice;
|
|
474
|
+
return {
|
|
475
|
+
...tokenDetails,
|
|
476
|
+
valueUsd,
|
|
477
|
+
value
|
|
478
|
+
};
|
|
479
|
+
});
|
|
480
|
+
if (destination.underlyingTokenSymbols.length === 1) {
|
|
481
|
+
const underlyingTokenAddress = tokensWithValue[0].tokenAddress;
|
|
482
|
+
if (underlyingTokenAddress) {
|
|
483
|
+
underlyingTokens = [
|
|
484
|
+
{
|
|
485
|
+
...getToken(underlyingTokenAddress, chainId),
|
|
486
|
+
valueUsd: debtValueHeldByVaultEth * baseAssetPrice,
|
|
487
|
+
value: debtValueHeldByVaultEth
|
|
488
|
+
}
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const isGenStrat = autopool.strategy.toLowerCase() === "0x000000000000000000000000000000000000dead" || autopool.strategy === "0x0000000000000000000000000000000000000000";
|
|
493
|
+
return {
|
|
494
|
+
...destination,
|
|
495
|
+
debtValueHeldByVaultUsd: debtValueHeldByVaultEth * baseAssetPrice,
|
|
496
|
+
debtValueHeldByVaultEth,
|
|
497
|
+
compositeReturn: isGenStrat ? genStratAprs?.[autopool.poolAddress]?.[destination.vaultAddress]?.apr || 0 : formatEtherNum(destination.compositeReturn),
|
|
498
|
+
debtValueHeldByVaultAllocation: debtValueHeldByVaultEth / totalAssets,
|
|
499
|
+
underlyingTokens,
|
|
500
|
+
poolName: formatPoolName(destination.lpTokenName),
|
|
501
|
+
exchange: getProtocol(destination.exchangeName)
|
|
502
|
+
};
|
|
503
|
+
});
|
|
504
|
+
const uniqueExchanges = Array.from(
|
|
505
|
+
new Set(
|
|
506
|
+
destinations.map((d) => getProtocol(d.exchangeName)).filter(Boolean)
|
|
507
|
+
)
|
|
508
|
+
);
|
|
509
|
+
const uniqueExchangesWithValueHeld = uniqueExchanges.map((exchange) => {
|
|
510
|
+
const exchangeName = exchange.name.toLowerCase();
|
|
511
|
+
let exchangeInfo = exchange;
|
|
512
|
+
const value = exchangeValues[exchangeName];
|
|
513
|
+
if (chainId === sonic.id) {
|
|
514
|
+
if (exchangeName === "balancerv3" || exchangeName === "balancer") {
|
|
515
|
+
exchangeInfo = BEETS_PROTOCOL;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
...exchangeInfo,
|
|
520
|
+
valueUsd: value * baseAssetPrice,
|
|
521
|
+
value,
|
|
522
|
+
allocation: value / totalAssets
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
const groupedExchanges = uniqueExchangesWithValueHeld.reduce(
|
|
526
|
+
(acc, exchange) => {
|
|
527
|
+
const exchangeName = exchange.name.toLowerCase();
|
|
528
|
+
const existingExchange = acc.find(
|
|
529
|
+
(e) => e.name.toLowerCase() === exchangeName
|
|
530
|
+
);
|
|
531
|
+
if (existingExchange) {
|
|
532
|
+
existingExchange.valueUsd += exchange.valueUsd;
|
|
533
|
+
existingExchange.value += exchange.value;
|
|
534
|
+
existingExchange.allocation += exchange.allocation;
|
|
535
|
+
} else {
|
|
536
|
+
acc.push(exchange);
|
|
537
|
+
}
|
|
538
|
+
return acc;
|
|
539
|
+
},
|
|
540
|
+
[]
|
|
541
|
+
);
|
|
542
|
+
const uniqueTokensWithValueHeldMap = destinations.flatMap((d) => d.underlyingTokens).reduce((acc, token) => {
|
|
543
|
+
if (acc[token.address]) {
|
|
544
|
+
acc[token.address].valueUsd += token.valueUsd;
|
|
545
|
+
acc[token.address].value += token.value;
|
|
546
|
+
} else {
|
|
547
|
+
acc[token.address] = { ...token };
|
|
548
|
+
}
|
|
549
|
+
return acc;
|
|
550
|
+
}, {});
|
|
551
|
+
const uniqueTokens = Object.values(uniqueTokensWithValueHeldMap).map(
|
|
552
|
+
(token) => {
|
|
553
|
+
let valueUsd = token.valueUsd;
|
|
554
|
+
let value = token.value;
|
|
555
|
+
const allocation = value / totalAssets;
|
|
556
|
+
return {
|
|
557
|
+
...token,
|
|
558
|
+
valueUsd,
|
|
559
|
+
value,
|
|
560
|
+
allocation
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
);
|
|
564
|
+
let UIBaseAsset = baseAsset;
|
|
565
|
+
if (baseAsset.symbol?.toLowerCase() === WETH_TOKEN.symbol.toLowerCase()) {
|
|
566
|
+
UIBaseAsset = ETH_TOKEN;
|
|
567
|
+
}
|
|
568
|
+
if (baseAsset.symbol?.toLowerCase() === WS_TOKEN.symbol.toLowerCase()) {
|
|
569
|
+
UIBaseAsset = S_TOKEN;
|
|
570
|
+
}
|
|
571
|
+
if (baseAsset.symbol?.toLowerCase() === WXPL_TOKEN.symbol.toLowerCase()) {
|
|
572
|
+
UIBaseAsset = XPL_TOKEN;
|
|
573
|
+
}
|
|
574
|
+
const isNew = (Date.now() / 1e3 - timestamp) / 60 / 60 / 24 < 45;
|
|
575
|
+
const aprs = autopoolsApr.find(
|
|
576
|
+
(autopoolApr) => getAddress(autopoolApr.id) === getAddress(autopool.poolAddress)
|
|
577
|
+
);
|
|
578
|
+
let baseApr = aprs?.currentApy;
|
|
579
|
+
let boostedApr = 0;
|
|
580
|
+
let extraApr = 0;
|
|
581
|
+
const formattedRewarder7DayMAApy = formatEtherNum(
|
|
582
|
+
BigInt(Number(aprs?.rewarder?.day7MAApy) || 0)
|
|
583
|
+
);
|
|
584
|
+
const formattedRewarder30DayMAApy = formatEtherNum(
|
|
585
|
+
BigInt(Number(aprs?.rewarder?.day30MAApy) || 0)
|
|
586
|
+
);
|
|
587
|
+
if (formattedRewarder7DayMAApy > 0) {
|
|
588
|
+
boostedApr = formattedRewarder7DayMAApy;
|
|
589
|
+
}
|
|
590
|
+
if (formattedRewarder30DayMAApy > 0) {
|
|
591
|
+
boostedApr = formattedRewarder30DayMAApy;
|
|
592
|
+
}
|
|
593
|
+
if (!baseApr) {
|
|
594
|
+
const weightedCrNum = destinations.reduce((acc, cur) => {
|
|
595
|
+
return acc + cur.debtValueHeldByVaultAllocation * cur.compositeReturn;
|
|
596
|
+
}, 0);
|
|
597
|
+
const periodicFeeBps = autopool.periodicFeeBps || 0n;
|
|
598
|
+
const streamingFeeBps = autopool.streamingFeeBps || 0n;
|
|
599
|
+
baseApr = (weightedCrNum / (1 - totalIdleAssets / totalAssets) - Number(formatUnits(periodicFeeBps, 4))) * (1 - Number(formatUnits(streamingFeeBps, 4)));
|
|
600
|
+
} else {
|
|
601
|
+
baseApr = Number(formatUnits(BigInt(baseApr), baseAsset.decimals));
|
|
602
|
+
}
|
|
603
|
+
if (!baseApr) {
|
|
604
|
+
baseApr = 0;
|
|
605
|
+
}
|
|
606
|
+
if (baseApr === 0) {
|
|
607
|
+
try {
|
|
608
|
+
const backupApr = await getBackupApr(chainId, autopool.poolAddress);
|
|
609
|
+
if (backupApr) {
|
|
610
|
+
baseApr = backupApr;
|
|
611
|
+
console.log("using backup apr", backupApr);
|
|
612
|
+
}
|
|
613
|
+
} catch (e) {
|
|
614
|
+
console.error(e);
|
|
615
|
+
console.log("unable to retrieve backup apr");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (baseApr === 0 && autopool.symbol.toLowerCase() === "baseusd") {
|
|
619
|
+
baseApr = 0.0914;
|
|
620
|
+
}
|
|
621
|
+
let extraRewards = [];
|
|
622
|
+
if (aprs?.rewarder?.extraRewarders?.length && aprs?.rewarder?.extraRewarders?.length > 0) {
|
|
623
|
+
extraRewards = aprs?.rewarder?.extraRewarders.map((reward) => {
|
|
624
|
+
const token = getToken(reward?.rewardToken?.id, chainId);
|
|
625
|
+
return {
|
|
626
|
+
...token,
|
|
627
|
+
apr: formatEtherNum(BigInt(reward.currentApy || 0))
|
|
628
|
+
};
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
if (autopool?.symbol?.toLowerCase() === "plasmausd") {
|
|
632
|
+
boostedApr = 0;
|
|
633
|
+
}
|
|
634
|
+
extraApr = extraRewards.reduce((acc, reward) => acc + reward.apr, 0);
|
|
635
|
+
const combinedApr = baseApr + boostedApr + extraApr;
|
|
636
|
+
let denominatedToken = ETH_TOKEN;
|
|
637
|
+
let useDenominatedValues = false;
|
|
638
|
+
const denominatedIn = aprs?.denominatedIn;
|
|
639
|
+
if (denominatedIn?.symbol?.toLowerCase() === "weth") {
|
|
640
|
+
denominatedToken = ETH_TOKEN;
|
|
641
|
+
} else {
|
|
642
|
+
denominatedToken = getToken(denominatedIn?.id);
|
|
643
|
+
if (denominatedToken) {
|
|
644
|
+
useDenominatedValues = true;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
let denominatedTokenPrice = 0;
|
|
648
|
+
const tokenSymbol = denominatedToken.symbol?.toUpperCase();
|
|
649
|
+
if (tokenSymbol in prices) {
|
|
650
|
+
denominatedTokenPrice = prices[tokenSymbol];
|
|
651
|
+
} else {
|
|
652
|
+
denominatedTokenPrice = await getTokenPrice({
|
|
653
|
+
chainId: denominatedToken.chainId,
|
|
654
|
+
tokenAddress: denominatedToken.address
|
|
655
|
+
}) || 0;
|
|
656
|
+
}
|
|
657
|
+
const navPerShareBaseAsset = formatUnitsNum(
|
|
658
|
+
autopool.navPerShare,
|
|
659
|
+
baseAsset.decimals
|
|
660
|
+
);
|
|
661
|
+
const assets = convertBaseAssetToTokenPricesAndDenom(
|
|
662
|
+
formatUnitsNum(autopool.totalAssets, baseAsset.decimals),
|
|
663
|
+
baseAssetPrice,
|
|
664
|
+
denominatedTokenPrice,
|
|
665
|
+
prices
|
|
666
|
+
);
|
|
667
|
+
const navPerShare = convertBaseAssetToTokenPricesAndDenom(
|
|
668
|
+
navPerShareBaseAsset,
|
|
669
|
+
baseAssetPrice,
|
|
670
|
+
denominatedTokenPrice,
|
|
671
|
+
prices
|
|
672
|
+
);
|
|
673
|
+
const idle = convertBaseAssetToTokenPricesAndDenom(
|
|
674
|
+
totalIdleAssets,
|
|
675
|
+
baseAssetPrice,
|
|
676
|
+
denominatedTokenPrice,
|
|
677
|
+
prices
|
|
678
|
+
);
|
|
679
|
+
const idleAllocation = totalIdleAssets / totalAssets;
|
|
680
|
+
const combinedDailyEarnings = convertBaseAssetToTokenPricesAndDenom(
|
|
681
|
+
totalAssets * combinedApr / 365,
|
|
682
|
+
baseAssetPrice,
|
|
683
|
+
denominatedTokenPrice,
|
|
684
|
+
prices
|
|
685
|
+
);
|
|
686
|
+
const baseDailyEarnings = convertBaseAssetToTokenPricesAndDenom(
|
|
687
|
+
totalAssets * baseApr / 365,
|
|
688
|
+
baseAssetPrice,
|
|
689
|
+
denominatedTokenPrice,
|
|
690
|
+
prices
|
|
691
|
+
);
|
|
692
|
+
const tokenOrder = [UIBaseAsset.symbol, ...UITokenOrder].filter(
|
|
693
|
+
(value, index, array) => array.indexOf(value) === index
|
|
694
|
+
);
|
|
695
|
+
const UITokens = uniqueTokens.reduce((acc, token) => {
|
|
696
|
+
try {
|
|
697
|
+
const parentAsset = token.extensions?.parentAsset;
|
|
698
|
+
if (parentAsset) {
|
|
699
|
+
const parentToken = ALL_TOKENS.find(
|
|
700
|
+
(t) => t.symbol.toLowerCase() === parentAsset.toLowerCase()
|
|
701
|
+
);
|
|
702
|
+
if (parentToken && !acc.some(
|
|
703
|
+
(t) => t?.address?.toLowerCase() === parentToken?.address?.toLowerCase()
|
|
704
|
+
)) {
|
|
705
|
+
acc.push({
|
|
706
|
+
...parentToken,
|
|
707
|
+
valueUsd: 0,
|
|
708
|
+
value: 0,
|
|
709
|
+
allocation: 0
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
} else if (!acc.some(
|
|
713
|
+
(t) => t?.address?.toLowerCase() === token?.address?.toLowerCase()
|
|
714
|
+
)) {
|
|
715
|
+
acc.push(token);
|
|
716
|
+
}
|
|
717
|
+
} catch (error) {
|
|
718
|
+
console.warn(
|
|
719
|
+
`Error processing token: ${token?.symbol || "unknown"}`,
|
|
720
|
+
error
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
return acc;
|
|
724
|
+
}, []).sort((a, b) => {
|
|
725
|
+
try {
|
|
726
|
+
const aIndex = tokenOrder.indexOf(a.symbol.toUpperCase());
|
|
727
|
+
const bIndex = tokenOrder.indexOf(b.symbol.toUpperCase());
|
|
728
|
+
if (aIndex !== -1 && bIndex !== -1) {
|
|
729
|
+
return aIndex - bIndex;
|
|
730
|
+
}
|
|
731
|
+
if (aIndex !== -1)
|
|
732
|
+
return -1;
|
|
733
|
+
if (bIndex !== -1)
|
|
734
|
+
return 1;
|
|
735
|
+
return 0;
|
|
736
|
+
} catch (error) {
|
|
737
|
+
console.warn("Error sorting tokens:", error);
|
|
738
|
+
return 0;
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
const UIExchanges = groupedExchanges.filter((exchange) => {
|
|
742
|
+
try {
|
|
743
|
+
return exchange.type === "Lending Market" || exchange.type === "DEX";
|
|
744
|
+
} catch (error) {
|
|
745
|
+
console.warn(
|
|
746
|
+
`Error filtering exchange: ${exchange?.name || "unknown"}`,
|
|
747
|
+
error
|
|
748
|
+
);
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
}).sort((a, b) => {
|
|
752
|
+
try {
|
|
753
|
+
const aIndex = protocolOrder.indexOf(a.name);
|
|
754
|
+
const bIndex = protocolOrder.indexOf(b.name);
|
|
755
|
+
return aIndex - bIndex;
|
|
756
|
+
} catch (error) {
|
|
757
|
+
console.warn("Error sorting exchanges:", error);
|
|
758
|
+
return 0;
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
const finalUIExchanges = UIExchanges.filter((exchange) => {
|
|
762
|
+
if (exchange.name === "BalancerV3") {
|
|
763
|
+
return !UIExchanges.some((e) => e.name === "Balancer");
|
|
764
|
+
}
|
|
765
|
+
return true;
|
|
766
|
+
});
|
|
767
|
+
const autopoolInfo = getAutopoolInfo(autopool.symbol);
|
|
768
|
+
if (autopoolInfo && !autopoolInfo.description) {
|
|
769
|
+
autopoolInfo.description = `Autopool featuring ${UIBaseAsset.symbol} deployed across integrated DEXs and lending protocols on ${getNetwork(chainId)?.name}.`;
|
|
770
|
+
}
|
|
771
|
+
return {
|
|
772
|
+
...autopool,
|
|
773
|
+
tvl,
|
|
774
|
+
totalAssets: assets,
|
|
775
|
+
destinations,
|
|
776
|
+
exchanges: groupedExchanges,
|
|
777
|
+
timestamp,
|
|
778
|
+
isNew,
|
|
779
|
+
extraRewarders: aprs?.rewarder?.extraRewarders,
|
|
780
|
+
createdAt: new Date(timestamp * 1e3),
|
|
781
|
+
baseAsset: {
|
|
782
|
+
...baseAsset,
|
|
783
|
+
price: baseAssetPrice
|
|
784
|
+
},
|
|
785
|
+
denomination: {
|
|
786
|
+
...denominatedToken,
|
|
787
|
+
price: denominatedTokenPrice
|
|
788
|
+
},
|
|
789
|
+
useDenomination: useDenominatedValues,
|
|
790
|
+
UIBaseAsset,
|
|
791
|
+
UITokens,
|
|
792
|
+
UIExchanges: finalUIExchanges,
|
|
793
|
+
tokens: uniqueTokens,
|
|
794
|
+
chain: getNetwork(chainId),
|
|
795
|
+
apr: {
|
|
796
|
+
base: baseApr,
|
|
797
|
+
boosted: boostedApr,
|
|
798
|
+
extraAprs: extraRewards,
|
|
799
|
+
combined: combinedApr,
|
|
800
|
+
hasBoostedApr: boostedApr > 1e-4,
|
|
801
|
+
hasExtraAprs: extraRewards.length > 0
|
|
802
|
+
},
|
|
803
|
+
dailyEarnings: {
|
|
804
|
+
combined: combinedDailyEarnings,
|
|
805
|
+
base: baseDailyEarnings
|
|
806
|
+
},
|
|
807
|
+
navPerShare,
|
|
808
|
+
idle: {
|
|
809
|
+
...idle,
|
|
810
|
+
allocation: idleAllocation,
|
|
811
|
+
token: UIBaseAsset
|
|
812
|
+
},
|
|
813
|
+
category: getAutopoolCategory(baseAsset.symbol),
|
|
814
|
+
...autopoolInfo
|
|
815
|
+
};
|
|
816
|
+
})
|
|
817
|
+
);
|
|
818
|
+
return autopools;
|
|
819
|
+
} catch (e) {
|
|
820
|
+
console.error(e);
|
|
821
|
+
return [];
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
var getAutopools = async (wagmiConfig, {
|
|
825
|
+
prices,
|
|
826
|
+
includeTestnet = false
|
|
827
|
+
}) => {
|
|
828
|
+
try {
|
|
829
|
+
const chains = getChainsForEnv({ includeTestnet });
|
|
830
|
+
const autopools = (await Promise.all(
|
|
831
|
+
chains.map(
|
|
832
|
+
(chain) => getChainAutopools(wagmiConfig, {
|
|
833
|
+
prices,
|
|
834
|
+
chainId: chain?.chainId
|
|
835
|
+
})
|
|
836
|
+
)
|
|
837
|
+
)).flat();
|
|
838
|
+
const sortedAutopoolsByTimestamp = autopools.sort(
|
|
839
|
+
(a, b) => b.timestamp - a.timestamp
|
|
840
|
+
);
|
|
841
|
+
if (includeTestnet) {
|
|
842
|
+
return sortedAutopoolsByTimestamp;
|
|
843
|
+
} else {
|
|
844
|
+
return sortedAutopoolsByTimestamp.filter((pool) => {
|
|
845
|
+
return AUTOPOOLS_WHITELIST_PROD.includes(getAddress(pool.poolAddress));
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
} catch (e) {
|
|
849
|
+
console.error(e);
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
var getChainUserAutopools = async ({
|
|
853
|
+
address,
|
|
854
|
+
chainId = 1
|
|
855
|
+
}) => {
|
|
856
|
+
const { GetUserVaultInfo } = getSdkByChainId(chainId);
|
|
857
|
+
try {
|
|
858
|
+
if (address) {
|
|
859
|
+
const { userInfo } = await GetUserVaultInfo({
|
|
860
|
+
address
|
|
861
|
+
});
|
|
862
|
+
return userInfo?.vaults || [];
|
|
863
|
+
}
|
|
864
|
+
return [];
|
|
865
|
+
} catch (e) {
|
|
866
|
+
console.error(e);
|
|
867
|
+
return [];
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
var BASE_ASSETS = [
|
|
871
|
+
{ ...ETH_TOKEN, symbol: "ETH", coinGeckoId: "ethereum" },
|
|
872
|
+
{ ...PXETH_TOKEN, symbol: "PXETH", coinGeckoId: "dinero-staked-eth" },
|
|
873
|
+
{ ...USDC_TOKEN, symbol: "USDC", coinGeckoId: "usd-coin" },
|
|
874
|
+
{ ...DOLA_TOKEN, symbol: "DOLA", coinGeckoId: "dola-usd" },
|
|
875
|
+
{ ...S_TOKEN, symbol: "S" },
|
|
876
|
+
{ ...EURC_TOKEN, symbol: "EURC", coinGeckoId: "euro-coin" },
|
|
877
|
+
{ ...USDT_TOKEN, symbol: "USDT", coinGeckoId: "tether" },
|
|
878
|
+
{ ...USDT0_TOKEN, symbol: "USDT0", coinGeckoId: "tether" }
|
|
879
|
+
];
|
|
880
|
+
var PRICED_TOKENS = [
|
|
881
|
+
...BASE_ASSETS,
|
|
882
|
+
{ ...TOKE_TOKEN, symbol: "TOKE" },
|
|
883
|
+
{ ...SILO_TOKEN, symbol: "SILO" },
|
|
884
|
+
{ ...XPL_TOKEN, address: WXPL_TOKEN.address, symbol: "XPL" },
|
|
885
|
+
{ ...USDT0_TOKEN, symbol: "USDT0" }
|
|
886
|
+
];
|
|
887
|
+
[
|
|
888
|
+
{ ...WETH_TOKEN, symbol: "WETH" },
|
|
889
|
+
{ ...WS_TOKEN, symbol: "WS" },
|
|
890
|
+
{ ...WXPL_TOKEN, symbol: "WXPL" }
|
|
891
|
+
];
|
|
892
|
+
var getUserAutopool = async (wagmiConfig, {
|
|
893
|
+
address,
|
|
894
|
+
autopool
|
|
895
|
+
}) => {
|
|
896
|
+
try {
|
|
897
|
+
if (autopool && address) {
|
|
898
|
+
const autopoolContract = {
|
|
899
|
+
address: autopool?.poolAddress,
|
|
900
|
+
abi: autopoolEthAbi,
|
|
901
|
+
chainId: autopool?.chain?.chainId
|
|
902
|
+
};
|
|
903
|
+
const [
|
|
904
|
+
{ result: autopoolRewarderContract },
|
|
905
|
+
{ result: pastRewarders },
|
|
906
|
+
{ result: unstakedPoolShares, error: unstakedPoolSharesError }
|
|
907
|
+
] = await readContracts(wagmiConfig, {
|
|
908
|
+
contracts: [
|
|
909
|
+
{
|
|
910
|
+
...autopoolContract,
|
|
911
|
+
functionName: "rewarder",
|
|
912
|
+
args: []
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
...autopoolContract,
|
|
916
|
+
functionName: "getPastRewarders",
|
|
917
|
+
args: []
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
...autopoolContract,
|
|
921
|
+
functionName: "balanceOf",
|
|
922
|
+
args: [address]
|
|
923
|
+
}
|
|
924
|
+
]
|
|
925
|
+
});
|
|
926
|
+
if (!autopoolRewarderContract) {
|
|
927
|
+
throw new Error("No rewarder contract found");
|
|
928
|
+
}
|
|
929
|
+
if (unstakedPoolSharesError) {
|
|
930
|
+
throw new Error("Error fetching unstaked pool shares");
|
|
931
|
+
}
|
|
932
|
+
const stakedPoolShares = await readContract(wagmiConfig, {
|
|
933
|
+
address: autopoolRewarderContract,
|
|
934
|
+
abi: erc20Abi,
|
|
935
|
+
functionName: "balanceOf",
|
|
936
|
+
args: [address],
|
|
937
|
+
chainId: autopool?.chain?.chainId
|
|
938
|
+
});
|
|
939
|
+
const stakedShares = formatEtherNum(stakedPoolShares);
|
|
940
|
+
const stakedNav = stakedShares * (autopool?.navPerShare.baseAsset || 0);
|
|
941
|
+
const stakedNavUsd = stakedShares * (autopool?.navPerShare.USD || 0);
|
|
942
|
+
const unstakedShares = formatEtherNum(unstakedPoolShares || 0n);
|
|
943
|
+
const unstakedNav = unstakedShares * (autopool?.navPerShare.USD || 0);
|
|
944
|
+
const unstakedNavUsd = unstakedShares * (autopool?.navPerShare.USD || 0);
|
|
945
|
+
const totalShares = unstakedShares + stakedShares;
|
|
946
|
+
const totalNav = totalShares * (autopool?.navPerShare.baseAsset || 0);
|
|
947
|
+
const totalNavUsd = totalShares * (autopool?.navPerShare.USD || 0);
|
|
948
|
+
const totalNavDenominated = totalShares * (autopool?.navPerShare.denom || 0);
|
|
949
|
+
let pastRewarderBalances = [];
|
|
950
|
+
if (pastRewarders && pastRewarders?.length > 0) {
|
|
951
|
+
const pastRewardBalances = pastRewarders.map((rewarder) => ({
|
|
952
|
+
address: rewarder,
|
|
953
|
+
abi: erc20Abi,
|
|
954
|
+
functionName: "balanceOf",
|
|
955
|
+
args: [address],
|
|
956
|
+
chainId: autopool?.chain?.chainId
|
|
957
|
+
}));
|
|
958
|
+
const pastRewards = await readContracts(wagmiConfig, {
|
|
959
|
+
contracts: pastRewardBalances
|
|
960
|
+
});
|
|
961
|
+
pastRewarderBalances = pastRewards.map(({ result }, index) => {
|
|
962
|
+
const balance = result;
|
|
963
|
+
const shares = formatEtherNum(result);
|
|
964
|
+
const nav = shares * (autopool?.navPerShare.baseAsset || 0);
|
|
965
|
+
const navUsd = shares * (autopool?.navPerShare.USD || 0);
|
|
966
|
+
return {
|
|
967
|
+
rewarderContract: pastRewarders[index],
|
|
968
|
+
balance,
|
|
969
|
+
shares,
|
|
970
|
+
nav,
|
|
971
|
+
navUsd
|
|
972
|
+
};
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
staked: {
|
|
977
|
+
balance: stakedPoolShares,
|
|
978
|
+
shares: stakedShares,
|
|
979
|
+
nav: stakedNav,
|
|
980
|
+
navUsd: stakedNavUsd
|
|
981
|
+
},
|
|
982
|
+
unstaked: {
|
|
983
|
+
balance: unstakedPoolShares,
|
|
984
|
+
shares: unstakedShares,
|
|
985
|
+
nav: unstakedNav,
|
|
986
|
+
navUsd: unstakedNavUsd
|
|
987
|
+
},
|
|
988
|
+
pastRewarderBalances,
|
|
989
|
+
totalShares,
|
|
990
|
+
totalNav,
|
|
991
|
+
totalNavUsd,
|
|
992
|
+
totalNavDenominated,
|
|
993
|
+
useDenomination: autopool?.useDenomination,
|
|
994
|
+
denomination: autopool?.denomination
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
staked: {
|
|
999
|
+
balance: 0n,
|
|
1000
|
+
shares: 0,
|
|
1001
|
+
nav: 0,
|
|
1002
|
+
navUsd: 0
|
|
1003
|
+
},
|
|
1004
|
+
unstaked: {
|
|
1005
|
+
balance: 0n,
|
|
1006
|
+
shares: 0,
|
|
1007
|
+
nav: 0,
|
|
1008
|
+
navUsd: 0
|
|
1009
|
+
},
|
|
1010
|
+
totalNavDenominated: 0,
|
|
1011
|
+
totalShares: 0,
|
|
1012
|
+
totalNav: 0,
|
|
1013
|
+
totalNavUsd: 0
|
|
1014
|
+
};
|
|
1015
|
+
} catch (e) {
|
|
1016
|
+
console.error(e);
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// functions/getUserAutopools.ts
|
|
1021
|
+
function accumulateMap(dest, delta, multiplier = 1) {
|
|
1022
|
+
for (const [key, val] of Object.entries(delta)) {
|
|
1023
|
+
dest[key] = (dest[key] ?? 0) + val * multiplier;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
var createInitialCurrencyValues = () => {
|
|
1027
|
+
const currencies = Object.fromEntries([
|
|
1028
|
+
...PRICED_TOKENS.map((token) => [token.symbol, 0]),
|
|
1029
|
+
["USD", 0]
|
|
1030
|
+
]);
|
|
1031
|
+
return currencies;
|
|
1032
|
+
};
|
|
1033
|
+
var initialAutopoolsValue = {
|
|
1034
|
+
nav: createInitialCurrencyValues(),
|
|
1035
|
+
supplied: createInitialCurrencyValues(),
|
|
1036
|
+
returns: createInitialCurrencyValues(),
|
|
1037
|
+
idle: { ...createInitialCurrencyValues(), allocation: 0 },
|
|
1038
|
+
avgDailyReturns: createInitialCurrencyValues(),
|
|
1039
|
+
apr: 0,
|
|
1040
|
+
totalDeposits: 0,
|
|
1041
|
+
totalWithdrawals: 0
|
|
1042
|
+
};
|
|
1043
|
+
var getUserAutopools = async ({
|
|
1044
|
+
address,
|
|
1045
|
+
includeTestnet = false,
|
|
1046
|
+
autopools,
|
|
1047
|
+
userActivity,
|
|
1048
|
+
prices,
|
|
1049
|
+
config
|
|
1050
|
+
}) => {
|
|
1051
|
+
try {
|
|
1052
|
+
const chains = getChainsForEnv({ includeTestnet });
|
|
1053
|
+
const userAutopools = (await Promise.all(
|
|
1054
|
+
chains.map(
|
|
1055
|
+
(chain) => getChainUserAutopools({
|
|
1056
|
+
address,
|
|
1057
|
+
chainId: chain.chainId
|
|
1058
|
+
})
|
|
1059
|
+
)
|
|
1060
|
+
)).flat();
|
|
1061
|
+
const userExchanges = {};
|
|
1062
|
+
const userTokens = {};
|
|
1063
|
+
const userPools = {};
|
|
1064
|
+
if (autopools && autopools.length > 0 && userAutopools.length > 0 && prices) {
|
|
1065
|
+
const userAutoDOLA = await getUserAutopool(config, {
|
|
1066
|
+
address,
|
|
1067
|
+
autopool: autopools.find((autopool) => autopool.symbol === "autoDOLA")
|
|
1068
|
+
});
|
|
1069
|
+
let categories = {
|
|
1070
|
+
usd: { ...initialAutopoolsValue },
|
|
1071
|
+
eth: { ...initialAutopoolsValue },
|
|
1072
|
+
crypto: { ...initialAutopoolsValue },
|
|
1073
|
+
stables: { ...initialAutopoolsValue }
|
|
1074
|
+
};
|
|
1075
|
+
const userAutopoolsWithData = userAutopools.map((userAutopool) => {
|
|
1076
|
+
const autopoolData = autopools.find(
|
|
1077
|
+
(autopool) => autopool.poolAddress.toLowerCase() === userAutopool.vaultAddress.toLowerCase()
|
|
1078
|
+
);
|
|
1079
|
+
if (autopoolData) {
|
|
1080
|
+
const isDOLA = autopoolData.symbol === "autoDOLA" && userAutoDOLA;
|
|
1081
|
+
const userShares = isDOLA ? userAutoDOLA?.totalShares : formatEtherNum(userAutopool?.totalShares);
|
|
1082
|
+
const totalVaultShares = formatEtherNum(autopoolData?.totalSupply);
|
|
1083
|
+
const userShareOfVault = userShares / totalVaultShares;
|
|
1084
|
+
const totalDeposits = formatUnitsNum(
|
|
1085
|
+
userActivity?.totals[userAutopool.vaultAddress]?.totalDeposits || 0n,
|
|
1086
|
+
autopoolData?.baseAsset.decimals
|
|
1087
|
+
);
|
|
1088
|
+
const totalWithdrawals = formatUnitsNum(
|
|
1089
|
+
userActivity?.totals[userAutopool.vaultAddress]?.totalWithdrawals || 0n,
|
|
1090
|
+
autopoolData?.baseAsset.decimals
|
|
1091
|
+
);
|
|
1092
|
+
const poolEvents = userActivity?.events.filter(
|
|
1093
|
+
(event) => event.vaultAddress === userAutopool.vaultAddress
|
|
1094
|
+
);
|
|
1095
|
+
let lastDeposit;
|
|
1096
|
+
if (poolEvents && poolEvents?.length > 0) {
|
|
1097
|
+
lastDeposit = convertTimestampToDate(
|
|
1098
|
+
poolEvents[poolEvents.length - 1].timestamp
|
|
1099
|
+
).toLocaleDateString("en-US", {
|
|
1100
|
+
day: "2-digit",
|
|
1101
|
+
month: "short",
|
|
1102
|
+
year: "numeric"
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
autopoolData?.exchanges.forEach((exchange) => {
|
|
1106
|
+
if (userExchanges[exchange.name]) {
|
|
1107
|
+
userExchanges[exchange.name].value += userShareOfVault * exchange.value;
|
|
1108
|
+
userExchanges[exchange.name].valueUsd += userShareOfVault * exchange.valueUsd;
|
|
1109
|
+
} else {
|
|
1110
|
+
userExchanges[exchange.name] = {
|
|
1111
|
+
...exchange,
|
|
1112
|
+
value: userShareOfVault * exchange.value,
|
|
1113
|
+
valueUsd: userShareOfVault * exchange.valueUsd
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
let categoryKey = autopoolData.category;
|
|
1118
|
+
autopoolData?.tokens.forEach((token) => {
|
|
1119
|
+
if (userTokens[token.address]) {
|
|
1120
|
+
userTokens[token.address].value += userShareOfVault * token.value;
|
|
1121
|
+
userTokens[token.address].valueUsd += userShareOfVault * token.valueUsd;
|
|
1122
|
+
} else {
|
|
1123
|
+
userTokens[token.address] = {
|
|
1124
|
+
...token,
|
|
1125
|
+
value: userShareOfVault * token.value,
|
|
1126
|
+
valueUsd: userShareOfVault * token.valueUsd
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
});
|
|
1130
|
+
autopoolData?.destinations.forEach((pool) => {
|
|
1131
|
+
if (userPools[pool.vaultAddress]) {
|
|
1132
|
+
userPools[pool.vaultAddress].debtValueHeldByVaultEth += userShareOfVault * pool.debtValueHeldByVaultEth;
|
|
1133
|
+
userPools[pool.vaultAddress].debtValueHeldByVaultUsd += userShareOfVault * pool.debtValueHeldByVaultUsd;
|
|
1134
|
+
} else {
|
|
1135
|
+
userPools[pool.vaultAddress] = {
|
|
1136
|
+
...pool,
|
|
1137
|
+
debtValueHeldByVaultEth: userShareOfVault * pool.debtValueHeldByVaultEth,
|
|
1138
|
+
debtValueHeldByVaultUsd: userShareOfVault * pool.debtValueHeldByVaultUsd
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
const userNav = userShares * autopoolData?.navPerShare.baseAsset;
|
|
1143
|
+
const userReturns = userNav + totalWithdrawals - totalDeposits;
|
|
1144
|
+
const userSupplied = totalDeposits - totalWithdrawals;
|
|
1145
|
+
const userIdle = userShareOfVault * autopoolData?.idle.baseAsset;
|
|
1146
|
+
let nav2 = convertBaseAssetToTokenPricesAndDenom(
|
|
1147
|
+
userNav,
|
|
1148
|
+
autopoolData?.baseAsset.price,
|
|
1149
|
+
autopoolData.denomination.price,
|
|
1150
|
+
prices
|
|
1151
|
+
);
|
|
1152
|
+
const returns2 = convertBaseAssetToTokenPricesAndDenom(
|
|
1153
|
+
userReturns,
|
|
1154
|
+
autopoolData?.baseAsset.price,
|
|
1155
|
+
autopoolData.denomination.price,
|
|
1156
|
+
prices
|
|
1157
|
+
);
|
|
1158
|
+
const supplied2 = convertBaseAssetToTokenPricesAndDenom(
|
|
1159
|
+
userSupplied,
|
|
1160
|
+
autopoolData?.baseAsset.price,
|
|
1161
|
+
autopoolData.denomination.price,
|
|
1162
|
+
prices
|
|
1163
|
+
);
|
|
1164
|
+
const idle2 = convertBaseAssetToTokenPricesAndDenom(
|
|
1165
|
+
userIdle,
|
|
1166
|
+
autopoolData?.baseAsset.price,
|
|
1167
|
+
autopoolData.denomination.price,
|
|
1168
|
+
prices
|
|
1169
|
+
);
|
|
1170
|
+
const prev = categories[categoryKey];
|
|
1171
|
+
const idleDelta = {
|
|
1172
|
+
[autopoolData.UIBaseAsset.symbol]: autopoolData.idle.baseAsset,
|
|
1173
|
+
USD: autopoolData.idle.USD
|
|
1174
|
+
};
|
|
1175
|
+
const navDelta = nav2;
|
|
1176
|
+
const returnsDelta = returns2;
|
|
1177
|
+
const suppliedDelta = supplied2;
|
|
1178
|
+
const updatedIdle = { ...prev.idle };
|
|
1179
|
+
accumulateMap(updatedIdle, idleDelta, userShareOfVault);
|
|
1180
|
+
updatedIdle.allocation = 0;
|
|
1181
|
+
const updatedNav = { ...prev.nav };
|
|
1182
|
+
accumulateMap(updatedNav, navDelta);
|
|
1183
|
+
const updatedReturns = { ...prev.returns };
|
|
1184
|
+
accumulateMap(updatedReturns, returnsDelta);
|
|
1185
|
+
const updatedSupplied = { ...prev.supplied };
|
|
1186
|
+
accumulateMap(updatedSupplied, suppliedDelta);
|
|
1187
|
+
categories[categoryKey] = {
|
|
1188
|
+
...prev,
|
|
1189
|
+
idle: updatedIdle,
|
|
1190
|
+
nav: updatedNav,
|
|
1191
|
+
returns: updatedReturns,
|
|
1192
|
+
supplied: updatedSupplied,
|
|
1193
|
+
totalDeposits: prev.totalDeposits + totalDeposits,
|
|
1194
|
+
totalWithdrawals: prev.totalWithdrawals + totalWithdrawals
|
|
1195
|
+
};
|
|
1196
|
+
const stakedBalance = isDOLA ? userAutoDOLA?.staked.balance : BigInt(userAutopool?.stakedShares);
|
|
1197
|
+
const stakedShares = isDOLA ? userAutoDOLA?.staked.shares : formatEtherNum(stakedBalance);
|
|
1198
|
+
const stakedNav = stakedShares * (autopoolData?.navPerShare.baseAsset || 0);
|
|
1199
|
+
const staked = convertBaseAssetToTokenPrices(
|
|
1200
|
+
stakedNav,
|
|
1201
|
+
autopoolData?.baseAsset.price,
|
|
1202
|
+
prices
|
|
1203
|
+
);
|
|
1204
|
+
const unstakedBalance = isDOLA ? userAutoDOLA?.unstaked.balance : BigInt(userAutopool?.walletShares);
|
|
1205
|
+
const unstakedShares = isDOLA ? userAutoDOLA?.unstaked.shares : formatEtherNum(unstakedBalance);
|
|
1206
|
+
const unstakedNav = unstakedShares * (autopoolData?.navPerShare.baseAsset || 0);
|
|
1207
|
+
const unstaked = convertBaseAssetToTokenPrices(
|
|
1208
|
+
unstakedNav,
|
|
1209
|
+
autopoolData?.baseAsset.price,
|
|
1210
|
+
prices
|
|
1211
|
+
);
|
|
1212
|
+
const stakedRatio = stakedShares / userShares;
|
|
1213
|
+
const unstakedRatio = 1 - stakedRatio;
|
|
1214
|
+
const isSilo = autopoolData?.symbol === "siloETH" || autopoolData?.symbol === "siloUSD";
|
|
1215
|
+
const baseApr = autopoolData?.apr?.base ?? 0;
|
|
1216
|
+
const stakedAprForBlend = isSilo ? baseApr : autopoolData?.apr?.combined ?? 0;
|
|
1217
|
+
const blendedApr = stakedRatio * stakedAprForBlend + unstakedRatio * baseApr;
|
|
1218
|
+
return {
|
|
1219
|
+
name: autopoolData?.name,
|
|
1220
|
+
symbol: autopoolData?.symbol,
|
|
1221
|
+
poolAddress: autopoolData?.poolAddress,
|
|
1222
|
+
shares: userShares,
|
|
1223
|
+
nav: nav2,
|
|
1224
|
+
returns: returns2,
|
|
1225
|
+
supplied: supplied2,
|
|
1226
|
+
idle: idle2,
|
|
1227
|
+
totalDeposits,
|
|
1228
|
+
totalWithdrawals,
|
|
1229
|
+
staked: {
|
|
1230
|
+
balance: stakedBalance,
|
|
1231
|
+
shares: stakedShares,
|
|
1232
|
+
nav: staked
|
|
1233
|
+
},
|
|
1234
|
+
unstaked: {
|
|
1235
|
+
balance: unstakedBalance,
|
|
1236
|
+
shares: unstakedShares,
|
|
1237
|
+
nav: unstaked
|
|
1238
|
+
},
|
|
1239
|
+
useDenomination: autopoolData?.useDenomination,
|
|
1240
|
+
baseApr,
|
|
1241
|
+
blendedApr,
|
|
1242
|
+
rewardsClaimed: userAutopool?.rewardsClaimed,
|
|
1243
|
+
lastDeposit,
|
|
1244
|
+
baseAsset: autopoolData?.UIBaseAsset,
|
|
1245
|
+
denomination: autopoolData?.denomination,
|
|
1246
|
+
category: categoryKey
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
let denominatedToken = ETH_TOKEN;
|
|
1251
|
+
const useDenomination = userAutopoolsWithData.filter((autopool) => autopool?.useDenomination).length === 1 && userAutopoolsWithData.length === 1;
|
|
1252
|
+
if (useDenomination) {
|
|
1253
|
+
const autopoolWithDenomination = userAutopoolsWithData.find(
|
|
1254
|
+
(autopool) => autopool?.useDenomination
|
|
1255
|
+
);
|
|
1256
|
+
if (autopoolWithDenomination) {
|
|
1257
|
+
denominatedToken = autopoolWithDenomination?.denomination;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
const nav = Object.values(categories).reduce((acc, { nav: nav2 }) => {
|
|
1261
|
+
return Object.keys(nav2).reduce((sumAcc, key) => {
|
|
1262
|
+
const typedKey = key;
|
|
1263
|
+
sumAcc[typedKey] = (sumAcc[typedKey] || 0) + nav2[typedKey];
|
|
1264
|
+
return sumAcc;
|
|
1265
|
+
}, acc);
|
|
1266
|
+
}, {});
|
|
1267
|
+
const idleWithTokenPrices = userAutopoolsWithData.reduce(
|
|
1268
|
+
(acc, userAutopool) => {
|
|
1269
|
+
if (!userAutopool)
|
|
1270
|
+
return acc;
|
|
1271
|
+
const baseAssetSymbol = userAutopool.baseAsset.symbol;
|
|
1272
|
+
const existingEntry = acc.find(
|
|
1273
|
+
(entry) => entry.token.symbol === baseAssetSymbol
|
|
1274
|
+
);
|
|
1275
|
+
if (existingEntry) {
|
|
1276
|
+
Object.entries(userAutopool.idle).forEach(([key, value]) => {
|
|
1277
|
+
if (key in existingEntry) {
|
|
1278
|
+
existingEntry[key] += value || 0;
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
} else {
|
|
1282
|
+
acc.push({
|
|
1283
|
+
...userAutopool.idle,
|
|
1284
|
+
token: userAutopool.baseAsset
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
return acc;
|
|
1288
|
+
},
|
|
1289
|
+
[]
|
|
1290
|
+
);
|
|
1291
|
+
const idle = idleWithTokenPrices.map((idle2) => ({
|
|
1292
|
+
...idle2,
|
|
1293
|
+
allocation: idle2.USD / nav.USD
|
|
1294
|
+
}));
|
|
1295
|
+
const returns = Object.values(categories).reduce((acc, { returns: returns2 }) => {
|
|
1296
|
+
return Object.keys(returns2).reduce((sumAcc, key) => {
|
|
1297
|
+
const typedKey = key;
|
|
1298
|
+
sumAcc[typedKey] = (sumAcc[typedKey] || 0) + returns2[typedKey];
|
|
1299
|
+
return sumAcc;
|
|
1300
|
+
}, acc);
|
|
1301
|
+
}, {});
|
|
1302
|
+
const supplied = Object.values(categories).reduce((acc, { supplied: supplied2 }) => {
|
|
1303
|
+
return Object.keys(supplied2).reduce((sumAcc, key) => {
|
|
1304
|
+
const typedKey = key;
|
|
1305
|
+
sumAcc[typedKey] = (sumAcc[typedKey] || 0) + supplied2[typedKey];
|
|
1306
|
+
return sumAcc;
|
|
1307
|
+
}, acc);
|
|
1308
|
+
}, {});
|
|
1309
|
+
const userExchangesWithAllocations = Object.values(userExchanges).map(
|
|
1310
|
+
(userExchange) => {
|
|
1311
|
+
return {
|
|
1312
|
+
...userExchange,
|
|
1313
|
+
allocation: userExchange.valueUsd / nav.USD
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
);
|
|
1317
|
+
const userTokensWithAllocations = Object.values(userTokens).map(
|
|
1318
|
+
(userToken) => {
|
|
1319
|
+
return {
|
|
1320
|
+
...userToken,
|
|
1321
|
+
allocation: userToken.valueUsd / nav.USD
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
);
|
|
1325
|
+
const userPoolsWithAllocations = Object.values(userPools).map(
|
|
1326
|
+
(userPool) => {
|
|
1327
|
+
return {
|
|
1328
|
+
...userPool,
|
|
1329
|
+
debtValueHeldByVaultAllocation: userPool.debtValueHeldByVaultUsd / nav.USD
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
);
|
|
1333
|
+
const userWeightedApr = userAutopoolsWithData.reduce((acc, autopool) => {
|
|
1334
|
+
if (!autopool)
|
|
1335
|
+
return acc;
|
|
1336
|
+
return acc + autopool?.blendedApr * (autopool?.nav.USD / nav.USD);
|
|
1337
|
+
}, 0);
|
|
1338
|
+
let [lowestApr, highestApr] = [0, 0];
|
|
1339
|
+
const aprValues = userAutopoolsWithData.map((autopool) => autopool?.blendedApr).filter((apr) => apr !== void 0 && apr !== null);
|
|
1340
|
+
lowestApr = Math.min(...aprValues);
|
|
1341
|
+
highestApr = Math.max(...aprValues);
|
|
1342
|
+
const avgDailyReturns = userWeightedApr / 365;
|
|
1343
|
+
const avgDailyReturnsUsd = avgDailyReturns * nav.USD;
|
|
1344
|
+
const activeBaseAssets = Object.values(categories).filter(
|
|
1345
|
+
(category) => category.nav.USD > 0
|
|
1346
|
+
);
|
|
1347
|
+
const hasMultipleBaseAssets = activeBaseAssets.length > 1;
|
|
1348
|
+
const categoryAprs = Object.keys(categories).reduce(
|
|
1349
|
+
(acc, categoryKey) => {
|
|
1350
|
+
const apr = userAutopoolsWithData.reduce((aprAcc, autopool) => {
|
|
1351
|
+
if (!autopool)
|
|
1352
|
+
return aprAcc;
|
|
1353
|
+
if (autopool?.category === categoryKey) {
|
|
1354
|
+
return aprAcc + autopool?.blendedApr * (autopool?.nav.USD / categories[categoryKey].nav.USD);
|
|
1355
|
+
}
|
|
1356
|
+
return aprAcc;
|
|
1357
|
+
}, 0);
|
|
1358
|
+
return {
|
|
1359
|
+
...acc,
|
|
1360
|
+
[categoryKey]: apr
|
|
1361
|
+
};
|
|
1362
|
+
},
|
|
1363
|
+
{}
|
|
1364
|
+
);
|
|
1365
|
+
Object.keys(categories).forEach((categoryKey) => {
|
|
1366
|
+
const categoryData = categories[categoryKey];
|
|
1367
|
+
const apr = categoryAprs[categoryKey] || 0;
|
|
1368
|
+
const dailyRate = apr / 365;
|
|
1369
|
+
categories[categoryKey] = {
|
|
1370
|
+
...categoryData,
|
|
1371
|
+
apr,
|
|
1372
|
+
avgDailyReturns: Object.keys(categoryData.nav).reduce((acc, key) => {
|
|
1373
|
+
const typedKey = key;
|
|
1374
|
+
acc[typedKey] = dailyRate * categoryData.nav[typedKey];
|
|
1375
|
+
return acc;
|
|
1376
|
+
}, {})
|
|
1377
|
+
};
|
|
1378
|
+
});
|
|
1379
|
+
return {
|
|
1380
|
+
nav,
|
|
1381
|
+
idle,
|
|
1382
|
+
supplied,
|
|
1383
|
+
returns,
|
|
1384
|
+
categories,
|
|
1385
|
+
exchanges: userExchangesWithAllocations,
|
|
1386
|
+
tokens: userTokensWithAllocations,
|
|
1387
|
+
pools: userPoolsWithAllocations,
|
|
1388
|
+
autopools: userAutopoolsWithData,
|
|
1389
|
+
avgDailyReturnsUsd,
|
|
1390
|
+
useDenomination,
|
|
1391
|
+
denominatedToken,
|
|
1392
|
+
weightedApr: userWeightedApr,
|
|
1393
|
+
lowestApr,
|
|
1394
|
+
highestApr,
|
|
1395
|
+
hasMultipleBaseAssets
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
} catch (e) {
|
|
1399
|
+
console.log(e);
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
var getChainUserAutopoolsHistory = async ({
|
|
1403
|
+
address,
|
|
1404
|
+
chainId = 1
|
|
1405
|
+
}) => {
|
|
1406
|
+
const { GetUserVaultsDayData } = getSdkByChainId(chainId);
|
|
1407
|
+
const oneYearAgoTimestamp = Math.floor(Date.now() / 1e3) - 365 * 24 * 60 * 60;
|
|
1408
|
+
try {
|
|
1409
|
+
if (address) {
|
|
1410
|
+
const { userVaultDayDatas } = await GetUserVaultsDayData({
|
|
1411
|
+
address,
|
|
1412
|
+
timestamp: oneYearAgoTimestamp
|
|
1413
|
+
});
|
|
1414
|
+
return userVaultDayDatas;
|
|
1415
|
+
}
|
|
1416
|
+
return [];
|
|
1417
|
+
} catch (e) {
|
|
1418
|
+
console.error(e);
|
|
1419
|
+
return [];
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
var getTokenValueDayDatas = async (tokenAddress, chainId = mainnet.id) => {
|
|
1423
|
+
const { GetTokenValueDayDatas } = getSdkByChainId(chainId);
|
|
1424
|
+
try {
|
|
1425
|
+
const { tokenValueDayDatas } = await GetTokenValueDayDatas({
|
|
1426
|
+
tokenAddress: tokenAddress.toLowerCase()
|
|
1427
|
+
});
|
|
1428
|
+
const historicalPrice = tokenValueDayDatas.map((tokenValueDayData) => {
|
|
1429
|
+
const date = convertTimestampToDate(
|
|
1430
|
+
tokenValueDayData.lastSnapshotTimestamp
|
|
1431
|
+
);
|
|
1432
|
+
const usdPrice = formatUnits(tokenValueDayData.priceInUsd, 8);
|
|
1433
|
+
return {
|
|
1434
|
+
timestamp: Number(tokenValueDayData.lastSnapshotTimestamp),
|
|
1435
|
+
date,
|
|
1436
|
+
price: usdPrice
|
|
1437
|
+
};
|
|
1438
|
+
});
|
|
1439
|
+
return historicalPrice;
|
|
1440
|
+
} catch (e) {
|
|
1441
|
+
console.error(e);
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
var hasCoinGeckoId = (asset) => typeof asset?.coinGeckoId === "string" && asset.coinGeckoId.length > 0;
|
|
1445
|
+
var getBlobHistoricalTokenPrices = async (tokenSymbol) => {
|
|
1446
|
+
const blobName = `historical_v2/${tokenSymbol}-latest-success.json`;
|
|
1447
|
+
const res = await getBlobData(blobName);
|
|
1448
|
+
if (!res?.data || !Array.isArray(res.data))
|
|
1449
|
+
return [];
|
|
1450
|
+
return res.data.map(({ timestamp, date, price }) => ({
|
|
1451
|
+
timestamp,
|
|
1452
|
+
date,
|
|
1453
|
+
price
|
|
1454
|
+
}));
|
|
1455
|
+
};
|
|
1456
|
+
var getHistoricalTokenPrices = async () => {
|
|
1457
|
+
const ETH_ADDRESS_IN_SUBGRAPH = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
1458
|
+
const historicalBaseAssetPrices = await Promise.all(
|
|
1459
|
+
BASE_ASSETS.map(async (baseAsset) => {
|
|
1460
|
+
if (!hasCoinGeckoId(baseAsset)) {
|
|
1461
|
+
const address = baseAsset.address === ETH_TOKEN.address ? ETH_ADDRESS_IN_SUBGRAPH : baseAsset.address;
|
|
1462
|
+
const prices2 = await getTokenValueDayDatas(
|
|
1463
|
+
address,
|
|
1464
|
+
baseAsset.chainId
|
|
1465
|
+
);
|
|
1466
|
+
return { ...baseAsset, prices: prices2 ?? [] };
|
|
1467
|
+
}
|
|
1468
|
+
const prices = await getBlobHistoricalTokenPrices(baseAsset.symbol);
|
|
1469
|
+
return { ...baseAsset, prices };
|
|
1470
|
+
})
|
|
1471
|
+
);
|
|
1472
|
+
const allTimestamps = /* @__PURE__ */ new Set();
|
|
1473
|
+
historicalBaseAssetPrices.forEach((asset) => {
|
|
1474
|
+
asset.prices?.forEach((priceData) => {
|
|
1475
|
+
if (priceData?.timestamp) {
|
|
1476
|
+
allTimestamps.add(priceData.timestamp);
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
});
|
|
1480
|
+
const sortedTimestamps = Array.from(allTimestamps).sort((a, b) => a - b);
|
|
1481
|
+
const historicalTokenPrices = sortedTimestamps.map(
|
|
1482
|
+
(timestamp) => {
|
|
1483
|
+
const prices = {};
|
|
1484
|
+
const baseAssetsWithUsd = [
|
|
1485
|
+
...BASE_ASSETS.map((asset) => asset.symbol),
|
|
1486
|
+
"USD"
|
|
1487
|
+
];
|
|
1488
|
+
const usdPrices = /* @__PURE__ */ new Map();
|
|
1489
|
+
baseAssetsWithUsd.forEach((asset) => {
|
|
1490
|
+
if (asset !== "USD") {
|
|
1491
|
+
const assetData = historicalBaseAssetPrices.find(
|
|
1492
|
+
(a) => a.symbol === asset
|
|
1493
|
+
);
|
|
1494
|
+
const priceData = findClosestTimestampEntry(
|
|
1495
|
+
assetData?.prices || [],
|
|
1496
|
+
timestamp
|
|
1497
|
+
);
|
|
1498
|
+
usdPrices.set(asset, priceData ? parseFloat(priceData.price) : 0);
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
baseAssetsWithUsd.forEach((asset1) => {
|
|
1502
|
+
prices[asset1] = {};
|
|
1503
|
+
baseAssetsWithUsd.forEach((asset2) => {
|
|
1504
|
+
if (asset1 === asset2) {
|
|
1505
|
+
prices[asset1][asset2] = 1;
|
|
1506
|
+
} else if (asset1 === "USD") {
|
|
1507
|
+
prices[asset1][asset2] = usdPrices.get(asset2) || 0;
|
|
1508
|
+
} else if (asset2 === "USD") {
|
|
1509
|
+
prices[asset1][asset2] = usdPrices.get(asset1) || 0;
|
|
1510
|
+
} else {
|
|
1511
|
+
const asset1UsdPrice = usdPrices.get(asset1) || 0;
|
|
1512
|
+
const asset2UsdPrice = usdPrices.get(asset2) || 0;
|
|
1513
|
+
prices[asset1][asset2] = asset2UsdPrice > 0 ? asset1UsdPrice / asset2UsdPrice : 0;
|
|
1514
|
+
}
|
|
1515
|
+
});
|
|
1516
|
+
});
|
|
1517
|
+
return {
|
|
1518
|
+
timestamp,
|
|
1519
|
+
date: new Date(timestamp * 1e3),
|
|
1520
|
+
prices
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
);
|
|
1524
|
+
return historicalTokenPrices;
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
// functions/getUserAutopoolsHistory.ts
|
|
1528
|
+
var ONE_DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
1529
|
+
function validateEnhancedUserHistoryEntry(entry) {
|
|
1530
|
+
return entry && typeof entry === "object" && entry.date instanceof Date && typeof entry.timestamp === "string" && Array.isArray(entry.autopools) && entry.nav && typeof entry.nav.ETH === "number" && typeof entry.nav.USD === "number" && typeof entry.nav.PXETH === "number" && typeof entry.nav.USDC === "number" && typeof entry.nav.EURC === "number" && typeof entry.nav.USDT === "number" && Array.isArray(entry.events) && typeof entry.differential === "number";
|
|
1531
|
+
}
|
|
1532
|
+
var getUserAutopoolsHistory = async (address, autopoolsHistory, events, includeTestnet = false) => {
|
|
1533
|
+
if (!autopoolsHistory) {
|
|
1534
|
+
throw new Error("No autopools history found");
|
|
1535
|
+
}
|
|
1536
|
+
if (!events) {
|
|
1537
|
+
throw new Error("No events found");
|
|
1538
|
+
}
|
|
1539
|
+
const chains = getChainsForEnv({ includeTestnet });
|
|
1540
|
+
const userHistory = (await Promise.all(
|
|
1541
|
+
chains.map(
|
|
1542
|
+
(chain) => getChainUserAutopoolsHistory({
|
|
1543
|
+
address,
|
|
1544
|
+
chainId: chain.chainId
|
|
1545
|
+
})
|
|
1546
|
+
)
|
|
1547
|
+
)).flat();
|
|
1548
|
+
const groupedByVault = userHistory.reduce((acc, data) => {
|
|
1549
|
+
const vaultId = data.vaultAddress.toLowerCase();
|
|
1550
|
+
if (!acc[vaultId]) {
|
|
1551
|
+
acc[vaultId] = [];
|
|
1552
|
+
}
|
|
1553
|
+
acc[vaultId].push({
|
|
1554
|
+
...data,
|
|
1555
|
+
date: new Date(data.timestamp * 1e3),
|
|
1556
|
+
timestamp: data.timestamp,
|
|
1557
|
+
vaultAddress: data.vaultAddress
|
|
1558
|
+
});
|
|
1559
|
+
return acc;
|
|
1560
|
+
}, {});
|
|
1561
|
+
const filledDataByVault = Object.entries(groupedByVault).reduce(
|
|
1562
|
+
(acc, [vaultId, vaultData]) => {
|
|
1563
|
+
acc[vaultId] = fillMissingDates(vaultData);
|
|
1564
|
+
return acc;
|
|
1565
|
+
},
|
|
1566
|
+
{}
|
|
1567
|
+
);
|
|
1568
|
+
const historicalBaseAssetPrices = await getHistoricalTokenPrices();
|
|
1569
|
+
const mergedHistory = Object.keys(filledDataByVault).reduce(
|
|
1570
|
+
(acc, vaultId) => {
|
|
1571
|
+
if (autopoolsHistory[vaultId]) {
|
|
1572
|
+
const autopoolHistory = autopoolsHistory[vaultId];
|
|
1573
|
+
const userHistory2 = filledDataByVault[vaultId];
|
|
1574
|
+
userHistory2.sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
1575
|
+
const mergedData = autopoolHistory.reduce((result2, dayData) => {
|
|
1576
|
+
const userHistoryData = findClosestDateEntry(
|
|
1577
|
+
userHistory2,
|
|
1578
|
+
dayData.date,
|
|
1579
|
+
ONE_DAY_IN_MS
|
|
1580
|
+
);
|
|
1581
|
+
if (userHistoryData) {
|
|
1582
|
+
const DECIMALS = BigInt(dayData.baseAsset.decimals);
|
|
1583
|
+
const SCALE = 10n ** DECIMALS;
|
|
1584
|
+
const sharesRatio = userHistoryData.totalShares / dayData.totalSupply;
|
|
1585
|
+
const sharesRatioBigInt = BigInt(
|
|
1586
|
+
Math.floor(sharesRatio * Number(SCALE))
|
|
1587
|
+
);
|
|
1588
|
+
const navBigInt = sharesRatioBigInt * BigInt(dayData.nav) / SCALE;
|
|
1589
|
+
const navNum = formatUnitsNum(
|
|
1590
|
+
navBigInt,
|
|
1591
|
+
dayData.baseAsset.decimals
|
|
1592
|
+
);
|
|
1593
|
+
if (!historicalBaseAssetPrices) {
|
|
1594
|
+
throw new Error("No historical price data found");
|
|
1595
|
+
}
|
|
1596
|
+
const historicalPriceData = findClosestTimestampEntry(
|
|
1597
|
+
historicalBaseAssetPrices,
|
|
1598
|
+
Number(dayData.timestamp)
|
|
1599
|
+
);
|
|
1600
|
+
if (!historicalPriceData) {
|
|
1601
|
+
throw new Error("No historical price data found");
|
|
1602
|
+
}
|
|
1603
|
+
let pricesOfBaseAsset = historicalPriceData.prices[dayData.baseAsset.symbol.toUpperCase()];
|
|
1604
|
+
if (!pricesOfBaseAsset) {
|
|
1605
|
+
pricesOfBaseAsset = historicalPriceData.prices[dayData.baseAsset.extensions?.parentAsset?.toUpperCase()];
|
|
1606
|
+
}
|
|
1607
|
+
let nav = {};
|
|
1608
|
+
nav = Object.keys(pricesOfBaseAsset).reduce((acc2, currency) => {
|
|
1609
|
+
acc2[currency] = navNum * pricesOfBaseAsset[currency];
|
|
1610
|
+
return acc2;
|
|
1611
|
+
}, {});
|
|
1612
|
+
result2.push({
|
|
1613
|
+
id: dayData.id + `-${address}`,
|
|
1614
|
+
vaultAddress: dayData.vault.id,
|
|
1615
|
+
timestamp: dayData.timestamp,
|
|
1616
|
+
baseAsset: dayData.baseAsset,
|
|
1617
|
+
date: dayData.date,
|
|
1618
|
+
nav,
|
|
1619
|
+
shares: userHistoryData.totalShares,
|
|
1620
|
+
rewardsClaimed: userHistoryData.rewardsClaimed
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
return result2;
|
|
1624
|
+
}, []);
|
|
1625
|
+
acc[vaultId] = mergedData;
|
|
1626
|
+
}
|
|
1627
|
+
return acc;
|
|
1628
|
+
},
|
|
1629
|
+
{}
|
|
1630
|
+
);
|
|
1631
|
+
const aggregatedHistoryArray = Object.values(mergedHistory).flat().reduce((acc, dayData) => {
|
|
1632
|
+
const timestampKey = dayData.timestamp;
|
|
1633
|
+
if (!acc[timestampKey]) {
|
|
1634
|
+
acc[timestampKey] = {
|
|
1635
|
+
timestamp: dayData.timestamp,
|
|
1636
|
+
nav: {
|
|
1637
|
+
ETH: 0,
|
|
1638
|
+
USD: 0,
|
|
1639
|
+
PXETH: 0,
|
|
1640
|
+
USDC: 0,
|
|
1641
|
+
EURC: 0,
|
|
1642
|
+
USDT: 0
|
|
1643
|
+
},
|
|
1644
|
+
date: dayData.date,
|
|
1645
|
+
autopools: {}
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
acc[timestampKey].autopools[dayData.vaultAddress] = dayData;
|
|
1649
|
+
acc[timestampKey].nav.USD += dayData.nav.USD;
|
|
1650
|
+
acc[timestampKey].nav.ETH += dayData.nav.ETH;
|
|
1651
|
+
acc[timestampKey].nav.PXETH += dayData.nav.PXETH;
|
|
1652
|
+
acc[timestampKey].nav.USDC += dayData.nav.USDC;
|
|
1653
|
+
acc[timestampKey].nav.EURC += dayData.nav.EURC;
|
|
1654
|
+
acc[timestampKey].nav.USDT += dayData.nav.USDT;
|
|
1655
|
+
return acc;
|
|
1656
|
+
}, {});
|
|
1657
|
+
let finalAggregatedHistoryArray = Object.keys(aggregatedHistoryArray).map(
|
|
1658
|
+
(dateKey) => ({
|
|
1659
|
+
date: aggregatedHistoryArray[dateKey].date,
|
|
1660
|
+
formattedDate: formatDateToReadable(aggregatedHistoryArray[dateKey].date),
|
|
1661
|
+
nav: {
|
|
1662
|
+
ETH: aggregatedHistoryArray[dateKey].nav.ETH,
|
|
1663
|
+
USD: aggregatedHistoryArray[dateKey].nav.USD,
|
|
1664
|
+
PXETH: aggregatedHistoryArray[dateKey].nav.PXETH,
|
|
1665
|
+
USDC: aggregatedHistoryArray[dateKey].nav.USDC,
|
|
1666
|
+
EURC: aggregatedHistoryArray[dateKey].nav.EURC,
|
|
1667
|
+
USDT: aggregatedHistoryArray[dateKey].nav.USDT
|
|
1668
|
+
},
|
|
1669
|
+
timestamp: aggregatedHistoryArray[dateKey].timestamp,
|
|
1670
|
+
autopools: Object.values(aggregatedHistoryArray[dateKey].autopools)
|
|
1671
|
+
})
|
|
1672
|
+
);
|
|
1673
|
+
let updatedAggregatedHistoryArray = finalAggregatedHistoryArray.map(
|
|
1674
|
+
(dayData) => {
|
|
1675
|
+
return {
|
|
1676
|
+
...dayData,
|
|
1677
|
+
nav: {
|
|
1678
|
+
ETH: dayData.nav.ETH,
|
|
1679
|
+
USD: dayData.nav.USD,
|
|
1680
|
+
PXETH: dayData.nav.PXETH,
|
|
1681
|
+
USDC: dayData.nav.USDC,
|
|
1682
|
+
EURC: dayData.nav.EURC,
|
|
1683
|
+
USDT: dayData.nav.USDT
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
);
|
|
1688
|
+
updatedAggregatedHistoryArray = updatedAggregatedHistoryArray.map(
|
|
1689
|
+
(dayData) => {
|
|
1690
|
+
const eventsForDay = events?.filter((event) => {
|
|
1691
|
+
const eventDate = new Date(Number(event.timestamp) * 1e3);
|
|
1692
|
+
return eventDate.getTime() >= dayData.date.getTime() && eventDate.getTime() < dayData.date.getTime() + 24 * 60 * 60 * 1e3;
|
|
1693
|
+
});
|
|
1694
|
+
const differential = eventsForDay.reduce(
|
|
1695
|
+
(sum, event) => sum + formatEtherNum(BigInt(event?.assetChange || 0n)),
|
|
1696
|
+
0
|
|
1697
|
+
);
|
|
1698
|
+
return {
|
|
1699
|
+
...dayData,
|
|
1700
|
+
events: eventsForDay,
|
|
1701
|
+
differential
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
);
|
|
1705
|
+
const result = updatedAggregatedHistoryArray;
|
|
1706
|
+
const allValid = result.every(validateEnhancedUserHistoryEntry);
|
|
1707
|
+
if (!allValid) {
|
|
1708
|
+
throw new Error(
|
|
1709
|
+
"Invalid history entry detected: missing required properties"
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
return result;
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
// functions/getRewardsPayloadV1.ts
|
|
1716
|
+
var getRewardsPayloadV1 = async (cycleHash, account, rewardsV1Url) => {
|
|
1717
|
+
const userRewardUrl = `${rewardsV1Url}/${cycleHash}/${account.toLowerCase()}.json`;
|
|
1718
|
+
try {
|
|
1719
|
+
const response = await fetch(userRewardUrl, { method: "GET" });
|
|
1720
|
+
if (!response.ok) {
|
|
1721
|
+
return null;
|
|
1722
|
+
}
|
|
1723
|
+
const data = await response.json();
|
|
1724
|
+
return data;
|
|
1725
|
+
} catch (e) {
|
|
1726
|
+
console.log("Error fetching rewards payload:", e);
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
// functions/getUserRewardsV1.ts
|
|
1732
|
+
var getUserRewardsV1 = async (wagmiConfig, {
|
|
1733
|
+
address,
|
|
1734
|
+
rewardsCycleIndex,
|
|
1735
|
+
rewardsV1,
|
|
1736
|
+
rewardsV1Url,
|
|
1737
|
+
rewardsV1Hash,
|
|
1738
|
+
chainId
|
|
1739
|
+
}) => {
|
|
1740
|
+
try {
|
|
1741
|
+
const [latestClaimableHash, cycleRewardsHash] = await readContract(
|
|
1742
|
+
wagmiConfig,
|
|
1743
|
+
{
|
|
1744
|
+
address: rewardsV1Hash,
|
|
1745
|
+
abi: rewardsV1HashAbi,
|
|
1746
|
+
functionName: "cycleHashes",
|
|
1747
|
+
args: [rewardsCycleIndex],
|
|
1748
|
+
chainId
|
|
1749
|
+
}
|
|
1750
|
+
);
|
|
1751
|
+
const rewardsPayload = await getRewardsPayloadV1(
|
|
1752
|
+
cycleRewardsHash,
|
|
1753
|
+
address,
|
|
1754
|
+
rewardsV1Url
|
|
1755
|
+
);
|
|
1756
|
+
const latestClaimablePayload = await getRewardsPayloadV1(
|
|
1757
|
+
latestClaimableHash,
|
|
1758
|
+
address,
|
|
1759
|
+
rewardsV1Url
|
|
1760
|
+
);
|
|
1761
|
+
if (latestClaimablePayload) {
|
|
1762
|
+
const {
|
|
1763
|
+
payload: { chainId: payloadChainId, cycle, wallet, amount }
|
|
1764
|
+
} = latestClaimablePayload;
|
|
1765
|
+
const claimable = await readContract(wagmiConfig, {
|
|
1766
|
+
address: rewardsV1,
|
|
1767
|
+
abi: rewardsV1Abi,
|
|
1768
|
+
functionName: "getClaimableAmount",
|
|
1769
|
+
args: [{ chainId: payloadChainId, cycle, wallet, amount }],
|
|
1770
|
+
chainId
|
|
1771
|
+
});
|
|
1772
|
+
return { claimable, rewardsPayload, latestClaimablePayload };
|
|
1773
|
+
}
|
|
1774
|
+
return { rewardsPayload, latestClaimablePayload };
|
|
1775
|
+
} catch (e) {
|
|
1776
|
+
console.log(e);
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
var getUserV1 = async (wagmiConfig, {
|
|
1780
|
+
currentCycleIndex,
|
|
1781
|
+
address,
|
|
1782
|
+
chainId
|
|
1783
|
+
}) => {
|
|
1784
|
+
const {
|
|
1785
|
+
stakingV1,
|
|
1786
|
+
rewardsV1Url,
|
|
1787
|
+
accTokeV1RewardsHash,
|
|
1788
|
+
rewardsV1Hash,
|
|
1789
|
+
accTokeV1Rewards,
|
|
1790
|
+
autoEthGuardedRewards,
|
|
1791
|
+
rewardsV1,
|
|
1792
|
+
missedTokeRewards
|
|
1793
|
+
} = getMainnetConfig(mainnet.id);
|
|
1794
|
+
try {
|
|
1795
|
+
const userStakedTokeV1 = await readContract(wagmiConfig, {
|
|
1796
|
+
address: stakingV1,
|
|
1797
|
+
abi: stakingV1Abi,
|
|
1798
|
+
functionName: "availableForWithdrawal",
|
|
1799
|
+
args: [address, 0n],
|
|
1800
|
+
chainId: mainnet.id
|
|
1801
|
+
});
|
|
1802
|
+
const tokeRewards = await getUserRewardsV1(wagmiConfig, {
|
|
1803
|
+
address,
|
|
1804
|
+
rewardsCycleIndex: currentCycleIndex - 1n,
|
|
1805
|
+
rewardsV1,
|
|
1806
|
+
rewardsV1Url,
|
|
1807
|
+
rewardsV1Hash,
|
|
1808
|
+
chainId
|
|
1809
|
+
});
|
|
1810
|
+
const ethRewards = await getUserRewardsV1(wagmiConfig, {
|
|
1811
|
+
address,
|
|
1812
|
+
rewardsCycleIndex: 306n,
|
|
1813
|
+
rewardsV1: accTokeV1Rewards,
|
|
1814
|
+
rewardsV1Url,
|
|
1815
|
+
rewardsV1Hash: accTokeV1RewardsHash,
|
|
1816
|
+
chainId
|
|
1817
|
+
});
|
|
1818
|
+
const autoEthGuardedRewardsPayload = await getRewardsPayloadV1(
|
|
1819
|
+
"QmcJgQ42aGTsqngSBa98qxnbv2CHyk9DmSg1jDD569bnpp",
|
|
1820
|
+
address,
|
|
1821
|
+
rewardsV1Url
|
|
1822
|
+
);
|
|
1823
|
+
const payloadChainId = autoEthGuardedRewardsPayload?.payload?.chainId;
|
|
1824
|
+
const cycle = autoEthGuardedRewardsPayload?.payload?.cycle;
|
|
1825
|
+
const wallet = autoEthGuardedRewardsPayload?.payload?.wallet;
|
|
1826
|
+
const amount = autoEthGuardedRewardsPayload?.payload?.amount;
|
|
1827
|
+
const claimableAutoEth = await readContract(wagmiConfig, {
|
|
1828
|
+
address: autoEthGuardedRewards,
|
|
1829
|
+
abi: rewardsV1Abi,
|
|
1830
|
+
functionName: "getClaimableAmount",
|
|
1831
|
+
args: [
|
|
1832
|
+
{
|
|
1833
|
+
chainId: payloadChainId || 0n,
|
|
1834
|
+
cycle: cycle || 0n,
|
|
1835
|
+
wallet: wallet || "0x0000000000000000000000000000000000000000",
|
|
1836
|
+
amount: amount || 0n
|
|
1837
|
+
}
|
|
1838
|
+
],
|
|
1839
|
+
chainId
|
|
1840
|
+
});
|
|
1841
|
+
const missedTokeRewardsPayload = await getRewardsPayloadV1(
|
|
1842
|
+
"QmRpVjVhFqbUTtLnQ4addEwBtvF2CC7t6rbQWYiju9nAqd",
|
|
1843
|
+
address,
|
|
1844
|
+
rewardsV1Url
|
|
1845
|
+
);
|
|
1846
|
+
let claimableMissedToke = 0n;
|
|
1847
|
+
if (missedTokeRewardsPayload) {
|
|
1848
|
+
const {
|
|
1849
|
+
payload: { chainId: payloadChainId2, cycle: cycle2, wallet: wallet2, amount: amount2 }
|
|
1850
|
+
} = missedTokeRewardsPayload;
|
|
1851
|
+
claimableMissedToke = await readContract(wagmiConfig, {
|
|
1852
|
+
address: missedTokeRewards,
|
|
1853
|
+
abi: rewardsV1Abi,
|
|
1854
|
+
functionName: "getClaimableAmount",
|
|
1855
|
+
args: [
|
|
1856
|
+
{
|
|
1857
|
+
chainId: payloadChainId2,
|
|
1858
|
+
cycle: cycle2,
|
|
1859
|
+
wallet: wallet2,
|
|
1860
|
+
amount: amount2 || 0n
|
|
1861
|
+
}
|
|
1862
|
+
],
|
|
1863
|
+
chainId
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1866
|
+
return {
|
|
1867
|
+
stakedToke: userStakedTokeV1,
|
|
1868
|
+
claimableToke: tokeRewards?.claimable,
|
|
1869
|
+
claimableEth: ethRewards?.claimable,
|
|
1870
|
+
claimableAutoEth,
|
|
1871
|
+
tokeRewardsPayload: tokeRewards?.rewardsPayload,
|
|
1872
|
+
ethRewardsPayload: ethRewards?.rewardsPayload,
|
|
1873
|
+
missedTokeRewardsPayload,
|
|
1874
|
+
autoEthGuardedRewardsPayload,
|
|
1875
|
+
claimableMissedToke
|
|
1876
|
+
};
|
|
1877
|
+
} catch (e) {
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
var networkToAlchemyUrl = (chainId, apiKey) => {
|
|
1881
|
+
switch (chainId) {
|
|
1882
|
+
case mainnet.id:
|
|
1883
|
+
return `https://eth-mainnet.g.alchemy.com/v2/${apiKey}`;
|
|
1884
|
+
case base.id:
|
|
1885
|
+
return `https://base-mainnet.g.alchemy.com/v2/${apiKey}`;
|
|
1886
|
+
case sonic.id:
|
|
1887
|
+
return `https://sonic-mainnet.g.alchemy.com/v2/${apiKey}`;
|
|
1888
|
+
default:
|
|
1889
|
+
throw new Error("Unsupported network");
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1892
|
+
var getUserTokenBalances = async ({
|
|
1893
|
+
address,
|
|
1894
|
+
apiKey,
|
|
1895
|
+
chainId
|
|
1896
|
+
}) => {
|
|
1897
|
+
if (!address)
|
|
1898
|
+
throw new Error("Address is not defined");
|
|
1899
|
+
if (!apiKey)
|
|
1900
|
+
throw new Error("Alchemy API key is not defined");
|
|
1901
|
+
const url = networkToAlchemyUrl(chainId, apiKey);
|
|
1902
|
+
const body = {
|
|
1903
|
+
jsonrpc: "2.0",
|
|
1904
|
+
method: "alchemy_getTokenBalances",
|
|
1905
|
+
params: [address],
|
|
1906
|
+
id: 1
|
|
1907
|
+
};
|
|
1908
|
+
const res = await fetch(url, {
|
|
1909
|
+
method: "POST",
|
|
1910
|
+
headers: { "Content-Type": "application/json" },
|
|
1911
|
+
body: JSON.stringify(body)
|
|
1912
|
+
});
|
|
1913
|
+
if (!res.ok)
|
|
1914
|
+
throw new Error(`Alchemy RPC error: ${res.statusText}`);
|
|
1915
|
+
const data = await res.json();
|
|
1916
|
+
if (!data.result || !data.result.tokenBalances) {
|
|
1917
|
+
throw new Error("No token balances found in response");
|
|
1918
|
+
}
|
|
1919
|
+
const tokenBalances = data.result.tokenBalances.reduce(
|
|
1920
|
+
(acc, balance) => {
|
|
1921
|
+
if (balance.tokenBalance && BigInt(balance.tokenBalance) !== BigInt(0)) {
|
|
1922
|
+
acc[balance.contractAddress] = hexToBigInt(
|
|
1923
|
+
balance.tokenBalance
|
|
1924
|
+
);
|
|
1925
|
+
}
|
|
1926
|
+
return acc;
|
|
1927
|
+
},
|
|
1928
|
+
{}
|
|
1929
|
+
);
|
|
1930
|
+
return tokenBalances;
|
|
1931
|
+
};
|
|
1932
|
+
var getChainUserActivity = async (address, chainId = 1) => {
|
|
1933
|
+
const { GetUserBalanceChangeHistory } = getSdkByChainId(chainId);
|
|
1934
|
+
try {
|
|
1935
|
+
const { userAutopoolBalanceChanges } = await GetUserBalanceChangeHistory({
|
|
1936
|
+
userAddress: address
|
|
1937
|
+
});
|
|
1938
|
+
let userActivityTotals = {};
|
|
1939
|
+
let events = [];
|
|
1940
|
+
userAutopoolBalanceChanges.forEach((activity) => {
|
|
1941
|
+
if (!userActivityTotals[activity.vaultAddress]) {
|
|
1942
|
+
userActivityTotals[activity.vaultAddress] = {
|
|
1943
|
+
totalDeposits: 0n,
|
|
1944
|
+
totalWithdrawals: 0n,
|
|
1945
|
+
totalStakes: 0n,
|
|
1946
|
+
totalUnstakes: 0n,
|
|
1947
|
+
chainId
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
activity.items.forEach((item) => {
|
|
1951
|
+
if (item.staked && item.assetChange > 0n) {
|
|
1952
|
+
userActivityTotals[activity.vaultAddress].totalStakes += BigInt(
|
|
1953
|
+
item.assetChange
|
|
1954
|
+
);
|
|
1955
|
+
} else if (item.staked && item.assetChange < 0n) {
|
|
1956
|
+
userActivityTotals[activity.vaultAddress].totalUnstakes += BigInt(
|
|
1957
|
+
BigInt(item.assetChange) * -1n
|
|
1958
|
+
);
|
|
1959
|
+
} else if (!item.staked && item.assetChange > 0n) {
|
|
1960
|
+
userActivityTotals[activity.vaultAddress].totalDeposits += BigInt(
|
|
1961
|
+
item.assetChange
|
|
1962
|
+
);
|
|
1963
|
+
} else if (!item.staked && item.assetChange < 0n) {
|
|
1964
|
+
userActivityTotals[activity.vaultAddress].totalWithdrawals += BigInt(
|
|
1965
|
+
BigInt(item.assetChange) * -1n
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
if (!item.staked) {
|
|
1969
|
+
events.push({
|
|
1970
|
+
timestamp: activity.timestamp,
|
|
1971
|
+
shareChange: item.shareChange,
|
|
1972
|
+
assetChange: item.assetChange,
|
|
1973
|
+
vaultAddress: activity.vaultAddress
|
|
1974
|
+
// staked: item.staked,
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
});
|
|
1978
|
+
});
|
|
1979
|
+
return { events, totals: userActivityTotals };
|
|
1980
|
+
} catch (e) {
|
|
1981
|
+
console.log(e);
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
|
|
1985
|
+
// functions/getUserActivity.ts
|
|
1986
|
+
var getUserActivity = async ({
|
|
1987
|
+
address,
|
|
1988
|
+
includeTestnet = false
|
|
1989
|
+
}) => {
|
|
1990
|
+
const chains = getChainsForEnv({ includeTestnet });
|
|
1991
|
+
const userActivities = await Promise.all(
|
|
1992
|
+
chains.map(
|
|
1993
|
+
(chain) => getChainUserActivity(address, chain.chainId)
|
|
1994
|
+
)
|
|
1995
|
+
);
|
|
1996
|
+
const mergedActivity = userActivities.reduce(
|
|
1997
|
+
(acc, chainActivity) => {
|
|
1998
|
+
if (chainActivity?.events) {
|
|
1999
|
+
acc.events.push(...chainActivity.events);
|
|
2000
|
+
}
|
|
2001
|
+
if (chainActivity?.totals) {
|
|
2002
|
+
acc.totals = { ...acc.totals, ...chainActivity.totals };
|
|
2003
|
+
}
|
|
2004
|
+
return acc;
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
events: [],
|
|
2008
|
+
totals: {}
|
|
2009
|
+
}
|
|
2010
|
+
);
|
|
2011
|
+
mergedActivity.events.sort((a, b) => a.timestamp - b.timestamp);
|
|
2012
|
+
return mergedActivity;
|
|
2013
|
+
};
|
|
2014
|
+
var systemRegistryFunctionNames = [
|
|
2015
|
+
"asyncSwapperRegistry",
|
|
2016
|
+
"autoPoolRouter",
|
|
2017
|
+
"autoPoolRegistry",
|
|
2018
|
+
"swapRouter",
|
|
2019
|
+
"weth"
|
|
2020
|
+
];
|
|
2021
|
+
var getSystemConfig = async (wagmiConfig, { systemRegistry }) => {
|
|
2022
|
+
const systemRegistryContract = {
|
|
2023
|
+
address: systemRegistry,
|
|
2024
|
+
abi: systemRegistryAbi
|
|
2025
|
+
};
|
|
2026
|
+
const systemRegistryCalls = systemRegistryFunctionNames.map(
|
|
2027
|
+
(functionName) => ({
|
|
2028
|
+
...systemRegistryContract,
|
|
2029
|
+
functionName
|
|
2030
|
+
})
|
|
2031
|
+
);
|
|
2032
|
+
try {
|
|
2033
|
+
const [
|
|
2034
|
+
{ result: asyncSwapperRegistry },
|
|
2035
|
+
{ result: autopoolRouter },
|
|
2036
|
+
{ result: autopoolRegistry },
|
|
2037
|
+
{ result: swapRouter }
|
|
2038
|
+
] = await readContracts(wagmiConfig, {
|
|
2039
|
+
contracts: systemRegistryCalls
|
|
2040
|
+
});
|
|
2041
|
+
return {
|
|
2042
|
+
asyncSwapperRegistry,
|
|
2043
|
+
autopoolRouter,
|
|
2044
|
+
autopoolRegistry,
|
|
2045
|
+
swapRouter
|
|
2046
|
+
};
|
|
2047
|
+
} catch (e) {
|
|
2048
|
+
console.log(e);
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
var getCurrentCycleId = async (wagmiConfig, {
|
|
2052
|
+
stoke,
|
|
2053
|
+
chainId
|
|
2054
|
+
}) => {
|
|
2055
|
+
return readContract(wagmiConfig, {
|
|
2056
|
+
address: stoke,
|
|
2057
|
+
abi: accTokeV1Abi,
|
|
2058
|
+
chainId,
|
|
2059
|
+
functionName: "getCurrentCycleID"
|
|
2060
|
+
});
|
|
2061
|
+
};
|
|
2062
|
+
|
|
2063
|
+
export { getAutopools, getCurrentCycleId, getEthPrice, getSystemConfig, getTokePrice, getTokenPrice, getUserActivity, getUserAutopools, getUserAutopoolsHistory, getUserTokenBalances, getUserV1, systemRegistryFunctionNames };
|