@tokemak/queries 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/functions/getAutopoolDayData.d.ts.map +1 -1
  2. package/dist/functions/getAutopoolHistory.d.ts.map +1 -1
  3. package/dist/functions/getAutopools.d.ts +3 -3
  4. package/dist/functions/getAutopools.d.ts.map +1 -1
  5. package/dist/functions/getAutopoolsRebalances.d.ts.map +1 -1
  6. package/dist/functions/getChainAutopools.d.ts +20 -18
  7. package/dist/functions/getChainAutopools.d.ts.map +1 -1
  8. package/dist/functions/getEthPriceAtBlock.d.ts +2 -2
  9. package/dist/functions/getEthPriceAtBlock.d.ts.map +1 -1
  10. package/dist/functions/getMultipleAutopoolRebalances.d.ts.map +1 -1
  11. package/dist/functions/getPoolsAndDestinations.d.ts +4 -2
  12. package/dist/functions/getPoolsAndDestinations.d.ts.map +1 -1
  13. package/dist/functions/getRebalanceStats.d.ts +8 -6
  14. package/dist/functions/getRebalanceStats.d.ts.map +1 -1
  15. package/dist/functions/getTokenPrices.d.ts +1 -1
  16. package/dist/functions/getTokenPrices.d.ts.map +1 -1
  17. package/dist/functions/getUserAutopoolBalanceChanges.d.ts.map +1 -1
  18. package/dist/functions/getUserAutopools.d.ts +1 -1
  19. package/dist/functions/getUserAutopools.d.ts.map +1 -1
  20. package/dist/functions/getUserSAuto.d.ts +1 -1
  21. package/dist/functions/getUserSAuto.d.ts.map +1 -1
  22. package/dist/functions/updateRebalanceStats.d.ts +2 -2
  23. package/dist/functions/updateRebalanceStats.d.ts.map +1 -1
  24. package/dist/index.js +307 -352
  25. package/dist/index.mjs +197 -245
  26. package/dist/safe.d.ts +9 -0
  27. package/dist/safe.d.ts.map +1 -0
  28. package/dist/safe.js +883 -0
  29. package/dist/safe.mjs +871 -0
  30. package/package.json +27 -16
  31. package/dist/functions/getBackupApr.d.ts +0 -2
  32. package/dist/functions/getBackupApr.d.ts.map +0 -1
  33. package/dist/functions/getBackupTokenPrices.d.ts +0 -6
  34. package/dist/functions/getBackupTokenPrices.d.ts.map +0 -1
  35. package/dist/functions/getPoolsAndDestinationsBackup.d.ts +0 -67
  36. package/dist/functions/getPoolsAndDestinationsBackup.d.ts.map +0 -1
package/dist/safe.mjs ADDED
@@ -0,0 +1,871 @@
1
+ // utils/mergeArraysWithKey.ts
2
+ function mergeArraysWithKey(objectsArray, arraysArray, key) {
3
+ if (objectsArray.length !== arraysArray.length) {
4
+ throw new Error("Both arrays must have the same length.");
5
+ }
6
+ return objectsArray.map((obj, index) => ({
7
+ ...obj,
8
+ [key]: arraysArray[index]
9
+ }));
10
+ }
11
+
12
+ // utils/mergeArrays.ts
13
+ function mergeArrays(objectsArray, objectsToMergeArray) {
14
+ if (objectsArray.length !== objectsToMergeArray.length) {
15
+ throw new Error("Both arrays must have the same length.");
16
+ }
17
+ return objectsArray.map((obj, index) => ({
18
+ ...obj,
19
+ ...objectsToMergeArray[index]
20
+ }));
21
+ }
22
+
23
+ // utils/getChainsForEnv.ts
24
+ import {
25
+ SUPPORTED_DEV_CHAINS,
26
+ SUPPORTED_PROD_CHAINS
27
+ } from "@tokemak/constants";
28
+ function getChainsForEnv({
29
+ includeTestnet = false
30
+ }) {
31
+ let chains;
32
+ chains = includeTestnet ? [...SUPPORTED_DEV_CHAINS] : [...SUPPORTED_PROD_CHAINS];
33
+ return chains;
34
+ }
35
+
36
+ // utils/getAutopoolCategory.ts
37
+ var ETH_BASE_ASSETS = ["ETH", "WETH"];
38
+ var USD_BASE_ASSETS = ["USDC", "DOLA", "USDT0"];
39
+ var EUR_BASE_ASSETS = ["EURC"];
40
+ var getAutopoolCategory = (baseAsset) => {
41
+ if (ETH_BASE_ASSETS.includes(baseAsset?.toUpperCase())) {
42
+ return "eth" /* ETH */;
43
+ } else if (USD_BASE_ASSETS.includes(baseAsset?.toUpperCase()) || EUR_BASE_ASSETS.includes(baseAsset?.toUpperCase())) {
44
+ return "stables" /* STABLES */;
45
+ }
46
+ return "crypto" /* CRYPTO */;
47
+ };
48
+
49
+ // utils/convertBaseAssetToTokenPrices.ts
50
+ var convertBaseAssetToTokenPrices = (baseAssetValue, baseAssetPrice, prices) => {
51
+ const baseAssetToTokenPrices = Object.fromEntries(
52
+ Object.entries(prices).map(([tokenSymbol, tokenPrice]) => [
53
+ tokenSymbol,
54
+ baseAssetPrice / tokenPrice
55
+ ])
56
+ );
57
+ return {
58
+ baseAsset: baseAssetValue,
59
+ USD: baseAssetValue * baseAssetPrice,
60
+ ...Object.fromEntries(
61
+ Object.entries(baseAssetToTokenPrices).map(([tokenSymbol, price]) => [
62
+ tokenSymbol.toUpperCase(),
63
+ baseAssetValue * price
64
+ ])
65
+ )
66
+ };
67
+ };
68
+
69
+ // utils/convertBaseAssetToTokenPricesAndDenom.ts
70
+ var convertBaseAssetToTokenPricesAndDenom = (baseAsset, baseAssetPrice, denomPrice, prices) => {
71
+ const baseAssetToDenom = baseAssetPrice / denomPrice;
72
+ return {
73
+ ...convertBaseAssetToTokenPrices(baseAsset, baseAssetPrice, prices),
74
+ denom: baseAsset * baseAssetToDenom
75
+ };
76
+ };
77
+
78
+ // utils/getAutopoolInfo.ts
79
+ import { ALL_AUTOPOOLS } from "@tokemak/tokenlist";
80
+ var getAutopoolInfo = (symbol) => {
81
+ const autopool = ALL_AUTOPOOLS.find((pool) => pool.symbol === symbol);
82
+ return autopool;
83
+ };
84
+
85
+ // utils/paginateQuery.ts
86
+ async function paginateQuery(queryFn, arrayKey, options = {}) {
87
+ const { first = 1e3, maxPages = 100, onPage } = options;
88
+ const results = [];
89
+ let skip = 0;
90
+ let pageNumber = 0;
91
+ let hasMoreData = true;
92
+ while (hasMoreData && pageNumber < maxPages) {
93
+ const pageResult = await queryFn({ first, skip });
94
+ const pageData = pageResult[arrayKey];
95
+ if (!pageData || Array.isArray(pageData) && pageData.length === 0) {
96
+ hasMoreData = false;
97
+ } else {
98
+ if (Array.isArray(pageData)) {
99
+ const pageArray = pageData;
100
+ results.push(...pageArray);
101
+ if (pageArray.length < first) {
102
+ hasMoreData = false;
103
+ }
104
+ } else {
105
+ return pageData;
106
+ }
107
+ onPage?.(pageData, pageNumber);
108
+ skip += first;
109
+ pageNumber++;
110
+ }
111
+ }
112
+ return results;
113
+ }
114
+
115
+ // functions/getChainAutopools.ts
116
+ import {
117
+ formatEtherNum,
118
+ formatPoolName,
119
+ formatUnitsNum,
120
+ getNetwork,
121
+ getProtocol,
122
+ getToken
123
+ } from "@tokemak/utils";
124
+ import { getAddress } from "viem";
125
+
126
+ // constants/tokenOrders.ts
127
+ var UITokenOrder = [
128
+ "ETH",
129
+ "WETH",
130
+ "STETH",
131
+ "WSTETH",
132
+ "RETH",
133
+ "SWETH",
134
+ "FRXETH",
135
+ "SFRXETH",
136
+ "EETH",
137
+ "CBETH",
138
+ "OSETH",
139
+ "PXETH",
140
+ "OETH",
141
+ "EZETH",
142
+ "RSETH",
143
+ "RSWETH",
144
+ "ETHX",
145
+ "RSWETH",
146
+ "PUFETH",
147
+ "USDC",
148
+ "DOLA",
149
+ "USDT",
150
+ "DAI"
151
+ ];
152
+ var protocolOrder = [
153
+ "Balancer",
154
+ "Curve",
155
+ "Aerodrome",
156
+ "Pendle",
157
+ "Aave",
158
+ "Morpho",
159
+ "Fluid"
160
+ ];
161
+
162
+ // functions/getGenStratAprs.ts
163
+ import { TOKEMAK_GENSTRAT_APRS_API_URL } from "@tokemak/constants";
164
+ var getGenStratAprs = async ({
165
+ chainId = 1
166
+ }) => {
167
+ try {
168
+ const params = new URLSearchParams({
169
+ chainId: chainId.toString(),
170
+ systemName: "gen3"
171
+ });
172
+ const response = await fetch(`${TOKEMAK_GENSTRAT_APRS_API_URL}?${params}`);
173
+ const data = await response.json();
174
+ if (data && data.success) {
175
+ return data.aprs.reduce((p, c) => {
176
+ if (!p[c.autopoolAddress]) {
177
+ p[c.autopoolAddress] = {};
178
+ }
179
+ for (const d of c.destinations) {
180
+ p[c.autopoolAddress][d.address] = {
181
+ name: d.name,
182
+ apr: d.apr
183
+ };
184
+ }
185
+ return p;
186
+ }, {});
187
+ } else {
188
+ return void 0;
189
+ }
190
+ } catch (error) {
191
+ console.log(error);
192
+ return void 0;
193
+ }
194
+ };
195
+
196
+ // functions/getTokenPrice.ts
197
+ import { TOKEMAK_SWAP_PRICING_URL } from "@tokemak/constants";
198
+
199
+ // functions/getDefillamaPrice.ts
200
+ var getDefillamaPrice = async (tokenAddress) => {
201
+ const response = await fetch(
202
+ `https://coins.llama.fi/prices/current/ethereum:${tokenAddress}`
203
+ );
204
+ const data = await response.json();
205
+ return data.coins[`ethereum:${tokenAddress}`].price;
206
+ };
207
+
208
+ // functions/getTokenPrice.ts
209
+ var getTokenPrice = async ({
210
+ chainId = 1,
211
+ tokenAddress,
212
+ includedSources,
213
+ excludedSources
214
+ }) => {
215
+ try {
216
+ const params = new URLSearchParams({
217
+ chainId: chainId.toString(),
218
+ systemName: "gen3",
219
+ token: tokenAddress
220
+ });
221
+ if (includedSources) {
222
+ params.set("includedSources", includedSources.join(","));
223
+ }
224
+ if (excludedSources) {
225
+ params.set("excludedSources", excludedSources.join(","));
226
+ }
227
+ const response = await fetch(`${TOKEMAK_SWAP_PRICING_URL}?${params}`);
228
+ const data = await response.json();
229
+ return data.price;
230
+ } catch (error) {
231
+ try {
232
+ const defillamaPrice = await getDefillamaPrice(tokenAddress);
233
+ return defillamaPrice;
234
+ } catch (error2) {
235
+ console.log(error2);
236
+ return void 0;
237
+ }
238
+ }
239
+ };
240
+
241
+ // functions/getChainAutopoolsApr.ts
242
+ import { AUTOPOOLS_APR_URL } from "@tokemak/constants";
243
+ var getChainAutopoolsApr = async (chainId) => {
244
+ try {
245
+ const response = await fetch(`${AUTOPOOLS_APR_URL}/${chainId}/gen3`, {
246
+ method: "GET",
247
+ headers: {
248
+ "Content-Type": "application/json"
249
+ }
250
+ });
251
+ if (!response.ok) {
252
+ throw new Error(
253
+ `Failed to fetch getChainAutopoolsApr: ${response.status}`
254
+ );
255
+ }
256
+ return await response.json();
257
+ } catch (e) {
258
+ console.error("Failed to fetch getChainAutopoolsApr:", e);
259
+ return void 0;
260
+ }
261
+ };
262
+
263
+ // functions/getChainAutopools.ts
264
+ import {
265
+ ALL_TOKENS,
266
+ BEETS_PROTOCOL,
267
+ ETH_TOKEN,
268
+ S_TOKEN,
269
+ WETH_TOKEN,
270
+ WS_TOKEN,
271
+ WXPL_TOKEN,
272
+ XPL_TOKEN
273
+ } from "@tokemak/tokenlist";
274
+ import { getSdkByChainId } from "@tokemak/graph-cli";
275
+ import { sonic } from "viem/chains";
276
+
277
+ // functions/getPoolsAndDestinations.ts
278
+ import { getCoreConfig } from "@tokemak/config";
279
+ import { lensAbi } from "@tokemak/abis";
280
+ var getPoolsAndDestinations = async (client, {
281
+ chainId,
282
+ account,
283
+ blockNumber
284
+ }) => {
285
+ try {
286
+ const { lens } = getCoreConfig(chainId);
287
+ const { autoPools, destinations } = await client.readContract({
288
+ address: lens,
289
+ abi: lensAbi,
290
+ functionName: "getPoolsAndDestinations",
291
+ account,
292
+ blockNumber
293
+ });
294
+ const autopoolsAndDestinations = mergeArraysWithKey(
295
+ autoPools,
296
+ destinations,
297
+ "destinations"
298
+ );
299
+ return autopoolsAndDestinations;
300
+ } catch (error) {
301
+ console.error(`Error on ${chainId} in getPoolsAndDestinations:`, error);
302
+ }
303
+ };
304
+
305
+ // functions/getChainAutopools.ts
306
+ import {
307
+ NEW_AUTOPOOL_THRESHOLD_DAYS,
308
+ DAYS_PER_YEAR,
309
+ DEAD_ADDRESS,
310
+ ZERO_ADDRESS
311
+ } from "@tokemak/constants";
312
+ var getChainAutopools = async (client, {
313
+ chainId,
314
+ prices,
315
+ account,
316
+ blockNumber
317
+ }) => {
318
+ const { GetVaultAddeds, GetAutopoolsInactiveDestinations } = getSdkByChainId(chainId);
319
+ try {
320
+ const { vaultAddeds } = await GetVaultAddeds();
321
+ const autopoolsAprResponse = await getChainAutopoolsApr(chainId);
322
+ const autopoolsApr = autopoolsAprResponse?.autopools || [];
323
+ const { GetAutopoolsApr } = getSdkByChainId(chainId);
324
+ const { autopools: autopoolsDenomination } = await GetAutopoolsApr();
325
+ const genStratAprs = await getGenStratAprs({
326
+ chainId
327
+ });
328
+ const autopoolsAndDestinations = await getPoolsAndDestinations(client, {
329
+ chainId,
330
+ account,
331
+ blockNumber
332
+ });
333
+ if (!autopoolsAndDestinations) {
334
+ throw new Error(`No autopools and destinations found for ${chainId}`);
335
+ }
336
+ const vaultAddedMapping = vaultAddeds.reduce(
337
+ (acc, vaultAdded) => {
338
+ acc[vaultAdded.vault.toLowerCase()] = Number(vaultAdded.blockTimestamp);
339
+ return acc;
340
+ },
341
+ {}
342
+ );
343
+ const autopools = await Promise.all(
344
+ autopoolsAndDestinations.map(async (autopool) => {
345
+ let baseAsset = getToken(autopool.baseAsset);
346
+ if (!baseAsset?.symbol) {
347
+ console.error(
348
+ "FIX THIS BEFORE PROD: base asset not found",
349
+ autopool.baseAsset
350
+ );
351
+ }
352
+ let baseAssetPrice = prices[(baseAsset?.symbol || "").toUpperCase()];
353
+ if (!baseAssetPrice) {
354
+ baseAssetPrice = await getTokenPrice({
355
+ chainId: baseAsset.chainId,
356
+ tokenAddress: baseAsset.address
357
+ }) || 0;
358
+ }
359
+ const timestamp = vaultAddedMapping[autopool.poolAddress.toLowerCase()];
360
+ const totalAssets = formatUnitsNum(
361
+ autopool.totalAssets,
362
+ baseAsset.decimals
363
+ );
364
+ const tvl = totalAssets * baseAssetPrice;
365
+ const totalIdleAssets = formatUnitsNum(
366
+ autopool.totalIdle,
367
+ baseAsset.decimals
368
+ );
369
+ const exchangeValues = {};
370
+ const destinations = autopool.destinations.map((destination) => {
371
+ const debtValueHeldByVaultEth = formatUnitsNum(
372
+ destination.debtValueHeldByVault,
373
+ baseAsset.decimals
374
+ );
375
+ if (!exchangeValues[destination.exchangeName.toLowerCase()]) {
376
+ exchangeValues[destination.exchangeName.toLowerCase()] = 0;
377
+ }
378
+ exchangeValues[destination.exchangeName.toLowerCase()] += debtValueHeldByVaultEth;
379
+ const tokensWithValue = mergeArrays(
380
+ destination.underlyingTokens,
381
+ destination.underlyingTokenValueHeld
382
+ );
383
+ let underlyingTokens = tokensWithValue.map((token) => {
384
+ const tokenDetails = getToken(token.tokenAddress);
385
+ let value = formatUnitsNum(
386
+ token.valueHeldInEth,
387
+ baseAsset.decimals
388
+ );
389
+ let valueUsd = value * baseAssetPrice;
390
+ return {
391
+ ...tokenDetails,
392
+ valueUsd,
393
+ value
394
+ };
395
+ });
396
+ if (destination.underlyingTokenSymbols.length === 1) {
397
+ const underlyingTokenAddress = tokensWithValue[0].tokenAddress;
398
+ if (underlyingTokenAddress) {
399
+ underlyingTokens = [
400
+ {
401
+ ...getToken(underlyingTokenAddress, chainId),
402
+ valueUsd: debtValueHeldByVaultEth * baseAssetPrice,
403
+ value: debtValueHeldByVaultEth
404
+ }
405
+ ];
406
+ }
407
+ }
408
+ const isGenStrat = autopool.strategy.toLowerCase() === DEAD_ADDRESS || autopool.strategy === ZERO_ADDRESS;
409
+ return {
410
+ ...destination,
411
+ debtValueHeldByVaultUsd: debtValueHeldByVaultEth * baseAssetPrice,
412
+ debtValueHeldByVaultEth,
413
+ compositeReturn: isGenStrat ? genStratAprs?.[autopool.poolAddress]?.[destination.vaultAddress]?.apr || 0 : formatEtherNum(destination.compositeReturn),
414
+ debtValueHeldByVaultAllocation: debtValueHeldByVaultEth / totalAssets,
415
+ underlyingTokens,
416
+ poolName: formatPoolName(destination.lpTokenName),
417
+ exchange: getProtocol(destination.exchangeName)
418
+ };
419
+ });
420
+ const HIDDEN_DESTINATION_SYMBOLS = ["USR", "WSTUSR"];
421
+ const filteredDestinations = destinations.filter(
422
+ (d) => !d.underlyingTokens.some(
423
+ (t) => HIDDEN_DESTINATION_SYMBOLS.includes(t.symbol?.toUpperCase())
424
+ )
425
+ );
426
+ const uniqueExchanges = Array.from(
427
+ new Set(
428
+ filteredDestinations.map((d) => getProtocol(d.exchangeName)).filter(Boolean)
429
+ )
430
+ );
431
+ const uniqueExchangesWithValueHeld = uniqueExchanges.map((exchange) => {
432
+ const exchangeName = exchange.name.toLowerCase();
433
+ let exchangeInfo = exchange;
434
+ const value = exchangeValues[exchangeName];
435
+ if (chainId === sonic.id) {
436
+ if (exchangeName === "balancerv3" || exchangeName === "balancer") {
437
+ exchangeInfo = BEETS_PROTOCOL;
438
+ }
439
+ }
440
+ return {
441
+ ...exchangeInfo,
442
+ valueUsd: value * baseAssetPrice,
443
+ value,
444
+ allocation: value / totalAssets
445
+ };
446
+ });
447
+ const groupedExchanges = uniqueExchangesWithValueHeld.reduce(
448
+ (acc, exchange) => {
449
+ const exchangeName = exchange.name.toLowerCase();
450
+ const existingExchange = acc.find(
451
+ (e) => e.name.toLowerCase() === exchangeName
452
+ );
453
+ if (existingExchange) {
454
+ existingExchange.valueUsd += exchange.valueUsd;
455
+ existingExchange.value += exchange.value;
456
+ existingExchange.allocation += exchange.allocation;
457
+ } else {
458
+ acc.push(exchange);
459
+ }
460
+ return acc;
461
+ },
462
+ []
463
+ );
464
+ const uniqueTokensWithValueHeldMap = filteredDestinations.flatMap((d) => d.underlyingTokens).reduce(
465
+ (acc, token) => {
466
+ if (acc[token.address]) {
467
+ acc[token.address].valueUsd += token.valueUsd;
468
+ acc[token.address].value += token.value;
469
+ } else {
470
+ acc[token.address] = { ...token };
471
+ }
472
+ return acc;
473
+ },
474
+ {}
475
+ );
476
+ const HIDDEN_TOKEN_SYMBOLS = ["USR", "WSTUSR"];
477
+ const uniqueTokens = Object.values(uniqueTokensWithValueHeldMap).filter(
478
+ (token) => !HIDDEN_TOKEN_SYMBOLS.includes(token.symbol?.toUpperCase())
479
+ ).map((token) => {
480
+ let valueUsd = token.valueUsd;
481
+ let value = token.value;
482
+ const allocation = value / totalAssets;
483
+ return {
484
+ ...token,
485
+ valueUsd,
486
+ value,
487
+ allocation
488
+ };
489
+ });
490
+ let UIBaseAsset = baseAsset;
491
+ if (baseAsset.symbol?.toLowerCase() === WETH_TOKEN.symbol.toLowerCase()) {
492
+ UIBaseAsset = ETH_TOKEN;
493
+ }
494
+ if (baseAsset.symbol?.toLowerCase() === WS_TOKEN.symbol.toLowerCase()) {
495
+ UIBaseAsset = S_TOKEN;
496
+ }
497
+ if (baseAsset.symbol?.toLowerCase() === WXPL_TOKEN.symbol.toLowerCase()) {
498
+ UIBaseAsset = XPL_TOKEN;
499
+ }
500
+ const isNew = (Date.now() / 1e3 - timestamp) / 60 / 60 / 24 < NEW_AUTOPOOL_THRESHOLD_DAYS;
501
+ const aprs = autopoolsApr.find(
502
+ (autopoolApr) => getAddress(autopoolApr.id) === getAddress(autopool.poolAddress)
503
+ );
504
+ const baseApr = aprs?.baseApy !== void 0 ? aprs.baseApy / 100 : void 0;
505
+ let extraApr = 0;
506
+ let extraRewards = [];
507
+ if (aprs?.rewards && aprs.rewards.length > 0) {
508
+ extraRewards = aprs.rewards.map((reward) => {
509
+ const token = getToken(reward.rewardToken, chainId);
510
+ return {
511
+ ...token,
512
+ apr: reward.rewardApy / 100
513
+ };
514
+ });
515
+ }
516
+ extraApr = extraRewards.reduce((acc, reward) => acc + reward.apr, 0);
517
+ const baseForMath = baseApr ?? 0;
518
+ const combinedApr = baseForMath + extraApr;
519
+ let denominatedToken = ETH_TOKEN;
520
+ let useDenominatedValues = false;
521
+ const denominationData = autopoolsDenomination.find(
522
+ (autopoolDenom) => getAddress(autopoolDenom.id) === getAddress(autopool.poolAddress)
523
+ );
524
+ const denominatedIn = denominationData?.denominatedIn;
525
+ if (denominatedIn?.symbol?.toLowerCase() === "weth") {
526
+ denominatedToken = ETH_TOKEN;
527
+ } else {
528
+ denominatedToken = getToken(denominatedIn?.id);
529
+ if (denominatedToken) {
530
+ useDenominatedValues = true;
531
+ }
532
+ }
533
+ let denominatedTokenPrice = 0;
534
+ const tokenSymbol = denominatedToken.symbol?.toUpperCase();
535
+ if (tokenSymbol in prices) {
536
+ denominatedTokenPrice = prices[tokenSymbol];
537
+ } else {
538
+ denominatedTokenPrice = await getTokenPrice({
539
+ chainId: denominatedToken.chainId,
540
+ tokenAddress: denominatedToken.address
541
+ }) || 0;
542
+ }
543
+ const navPerShareBaseAsset = formatUnitsNum(
544
+ autopool.navPerShare,
545
+ baseAsset.decimals
546
+ );
547
+ const assets = convertBaseAssetToTokenPricesAndDenom(
548
+ formatUnitsNum(autopool.totalAssets, baseAsset.decimals),
549
+ baseAssetPrice,
550
+ denominatedTokenPrice,
551
+ prices
552
+ );
553
+ const navPerShare = convertBaseAssetToTokenPricesAndDenom(
554
+ navPerShareBaseAsset,
555
+ baseAssetPrice,
556
+ denominatedTokenPrice,
557
+ prices
558
+ );
559
+ const idle = convertBaseAssetToTokenPricesAndDenom(
560
+ totalIdleAssets,
561
+ baseAssetPrice,
562
+ denominatedTokenPrice,
563
+ prices
564
+ );
565
+ const idleAllocation = totalIdleAssets / totalAssets;
566
+ const combinedDailyEarnings = convertBaseAssetToTokenPricesAndDenom(
567
+ totalAssets * combinedApr / DAYS_PER_YEAR,
568
+ baseAssetPrice,
569
+ denominatedTokenPrice,
570
+ prices
571
+ );
572
+ const baseDailyEarnings = convertBaseAssetToTokenPricesAndDenom(
573
+ totalAssets * baseForMath / DAYS_PER_YEAR,
574
+ baseAssetPrice,
575
+ denominatedTokenPrice,
576
+ prices
577
+ );
578
+ const tokenOrder = [UIBaseAsset.symbol, ...UITokenOrder].filter(
579
+ (value, index, array) => array.indexOf(value) === index
580
+ );
581
+ const UITokens = uniqueTokens.reduce(
582
+ (acc, token) => {
583
+ try {
584
+ const parentAsset = token.extensions?.parentAsset;
585
+ if (parentAsset) {
586
+ const parentToken = ALL_TOKENS.find(
587
+ (t) => t.symbol.toLowerCase() === parentAsset.toLowerCase()
588
+ );
589
+ if (parentToken && !acc.some(
590
+ (t) => t?.address?.toLowerCase() === parentToken?.address?.toLowerCase()
591
+ )) {
592
+ acc.push({
593
+ ...parentToken,
594
+ valueUsd: 0,
595
+ value: 0,
596
+ allocation: 0
597
+ });
598
+ }
599
+ } else if (!acc.some(
600
+ (t) => t?.address?.toLowerCase() === token?.address?.toLowerCase()
601
+ )) {
602
+ acc.push(token);
603
+ }
604
+ } catch (error) {
605
+ console.warn(
606
+ `Error processing token: ${token?.symbol || "unknown"}`,
607
+ error
608
+ );
609
+ }
610
+ return acc;
611
+ },
612
+ []
613
+ ).sort((a, b) => {
614
+ try {
615
+ const aIndex = tokenOrder.indexOf(a.symbol.toUpperCase());
616
+ const bIndex = tokenOrder.indexOf(b.symbol.toUpperCase());
617
+ if (aIndex !== -1 && bIndex !== -1) {
618
+ return aIndex - bIndex;
619
+ }
620
+ if (aIndex !== -1) return -1;
621
+ if (bIndex !== -1) return 1;
622
+ return 0;
623
+ } catch (error) {
624
+ console.warn("Error sorting tokens:", error);
625
+ return 0;
626
+ }
627
+ });
628
+ const UIExchanges = groupedExchanges.filter((exchange) => {
629
+ try {
630
+ return exchange.type === "Lending Market" || exchange.type === "DEX";
631
+ } catch (error) {
632
+ console.warn(
633
+ `Error filtering exchange: ${exchange?.name || "unknown"}`,
634
+ error
635
+ );
636
+ return false;
637
+ }
638
+ }).sort((a, b) => {
639
+ try {
640
+ const aIndex = protocolOrder.indexOf(a.name);
641
+ const bIndex = protocolOrder.indexOf(b.name);
642
+ return aIndex - bIndex;
643
+ } catch (error) {
644
+ console.warn("Error sorting exchanges:", error);
645
+ return 0;
646
+ }
647
+ });
648
+ const finalUIExchanges = UIExchanges.filter((exchange) => {
649
+ if (exchange.name === "BalancerV3") {
650
+ return !UIExchanges.some((e) => e.name === "Balancer");
651
+ }
652
+ return true;
653
+ });
654
+ const autopoolInfo = getAutopoolInfo(autopool.symbol);
655
+ if (autopoolInfo && !autopoolInfo.description) {
656
+ autopoolInfo.description = `Autopool featuring ${UIBaseAsset.symbol} deployed across integrated DEXs and lending protocols on ${getNetwork(chainId)?.name}.`;
657
+ }
658
+ return {
659
+ ...autopool,
660
+ tvl,
661
+ totalAssets: assets,
662
+ destinations: filteredDestinations,
663
+ exchanges: groupedExchanges,
664
+ timestamp,
665
+ isNew,
666
+ extraRewarders: denominationData?.rewarder?.extraRewarders,
667
+ autopoolRewarderDisabled: aprs?.autopoolRewarderDisabled ?? false,
668
+ createdAt: new Date(timestamp * 1e3),
669
+ baseAsset: {
670
+ ...baseAsset,
671
+ price: baseAssetPrice
672
+ },
673
+ denomination: {
674
+ ...denominatedToken,
675
+ price: denominatedTokenPrice
676
+ },
677
+ useDenomination: useDenominatedValues,
678
+ UIBaseAsset,
679
+ UITokens,
680
+ UIExchanges: finalUIExchanges,
681
+ tokens: uniqueTokens,
682
+ chain: getNetwork(chainId),
683
+ apr: {
684
+ base: baseApr ?? null,
685
+ extraAprs: extraRewards,
686
+ combined: combinedApr,
687
+ hasExtraAprs: extraRewards.length > 0
688
+ },
689
+ dailyEarnings: {
690
+ combined: combinedDailyEarnings,
691
+ base: baseDailyEarnings
692
+ },
693
+ navPerShare,
694
+ idle: {
695
+ ...idle,
696
+ allocation: idleAllocation,
697
+ token: UIBaseAsset
698
+ },
699
+ category: getAutopoolCategory(baseAsset.symbol),
700
+ ...autopoolInfo,
701
+ isShutdown: autopool.symbol === "sonicUSD" ? false : autopool.isShutdown
702
+ };
703
+ })
704
+ );
705
+ return autopools;
706
+ } catch (e) {
707
+ console.error(e);
708
+ return [];
709
+ }
710
+ };
711
+
712
+ // functions/getEthPriceAtBlock.ts
713
+ import { getCoreConfig as getCoreConfig2 } from "@tokemak/config";
714
+ import { rootPriceOracleAbi } from "@tokemak/abis";
715
+ import { USDC_TOKEN } from "@tokemak/tokenlist";
716
+ var getEthPriceAtBlock = async (client, blockNumber, chainId, account) => {
717
+ const config = getCoreConfig2(chainId);
718
+ const rootPriceOracle = config.rootPriceOracle;
719
+ const weth = config.weth;
720
+ const usdc = USDC_TOKEN.extensions?.bridgeInfo?.[chainId]?.tokenAddress || USDC_TOKEN.address;
721
+ const priceAtBlock = await client.readContract({
722
+ address: rootPriceOracle,
723
+ abi: rootPriceOracleAbi,
724
+ functionName: "getPriceInQuote",
725
+ args: [weth, usdc],
726
+ blockNumber,
727
+ account
728
+ });
729
+ return priceAtBlock;
730
+ };
731
+
732
+ // functions/getRebalanceStats.ts
733
+ import { getSdkByChainId as getSdkByChainId2 } from "@tokemak/graph-cli";
734
+ import { formatEtherNum as formatEtherNum2, formatUnitsNum as formatUnitsNum2 } from "@tokemak/utils";
735
+ import { USDC_TOKEN as USDC_TOKEN2 } from "@tokemak/tokenlist";
736
+ import { sonic as sonic2 } from "viem/chains";
737
+ var BATCH_SIZE = 500;
738
+ var fetchChainRebalances = async (chainId) => {
739
+ const { GetAllAutopoolRebalances } = getSdkByChainId2(chainId);
740
+ const allRebalances = await paginateQuery(
741
+ GetAllAutopoolRebalances,
742
+ "autopoolRebalances"
743
+ );
744
+ if (allRebalances.length === 0) {
745
+ return [];
746
+ }
747
+ return allRebalances;
748
+ };
749
+ function inferBaseAssetDecimals(rebalance, chainId) {
750
+ if (BigInt(rebalance.tokenOutValueBaseAsset) === BigInt(rebalance.tokenOutValueInEth)) {
751
+ return 18;
752
+ }
753
+ if (chainId === sonic2.id) {
754
+ return rebalance.tokenOut.decimals;
755
+ }
756
+ return USDC_TOKEN2.decimals;
757
+ }
758
+ var getRebalanceValueUsd = async (rebalance, chainId, client, account) => {
759
+ const ethWei = BigInt(rebalance.tokenOutValueInEth || "0");
760
+ if (ethWei === 0n) return null;
761
+ try {
762
+ const price = await getEthPriceAtBlock(
763
+ client,
764
+ BigInt(rebalance.blockNumber),
765
+ chainId,
766
+ account
767
+ );
768
+ const ethUsd = Number(formatUnitsNum2(price, USDC_TOKEN2.decimals));
769
+ const ethAmt = Number(formatEtherNum2(ethWei));
770
+ const usd = ethAmt * ethUsd;
771
+ return usd;
772
+ } catch (e) {
773
+ console.warn(`WETH/USDC oracle unavailable for chainId: ${chainId}`);
774
+ return null;
775
+ }
776
+ };
777
+ var processRebalance = async (rebalance, chainId, client, account) => {
778
+ const baseDecimals = inferBaseAssetDecimals(rebalance, chainId);
779
+ const baseAssetAmount = Number(
780
+ formatUnitsNum2(
781
+ BigInt(rebalance.tokenOutValueBaseAsset || "0"),
782
+ baseDecimals
783
+ )
784
+ );
785
+ const ethPathUsd = await getRebalanceValueUsd(
786
+ rebalance,
787
+ chainId,
788
+ client,
789
+ account
790
+ );
791
+ if (ethPathUsd != null) {
792
+ return {
793
+ autopool: rebalance.autopool,
794
+ timestamp: rebalance.timestamp,
795
+ blockNumber: rebalance.blockNumber,
796
+ chainId,
797
+ valueInUsd: ethPathUsd,
798
+ valueInAsset: baseAssetAmount
799
+ };
800
+ }
801
+ return {
802
+ autopool: rebalance.autopool,
803
+ timestamp: rebalance.timestamp,
804
+ blockNumber: rebalance.blockNumber,
805
+ chainId,
806
+ valueInUsd: baseAssetAmount,
807
+ valueInAsset: baseAssetAmount
808
+ };
809
+ };
810
+ var processRebalancesInBatches = async (rebalances, chainId, client, account) => {
811
+ const processedRebalances = [];
812
+ for (let i = 0; i < rebalances.length; i += BATCH_SIZE) {
813
+ const batch = rebalances.slice(i, i + BATCH_SIZE);
814
+ const batchPromises = batch.map(
815
+ async (rebalance) => processRebalance(rebalance, chainId, client, account)
816
+ );
817
+ const batchResults = await Promise.all(batchPromises);
818
+ processedRebalances.push(...batchResults);
819
+ console.log(
820
+ `Processed ${Math.min(i + BATCH_SIZE, rebalances.length)} of ${rebalances.length} rebalances...`
821
+ );
822
+ if (i + BATCH_SIZE < rebalances.length) {
823
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
824
+ }
825
+ }
826
+ return processedRebalances;
827
+ };
828
+ var calculateRebalanceStats = (rebalances) => {
829
+ const totalRebalances = rebalances.length;
830
+ const totalRebalanceVolume = rebalances.reduce(
831
+ (acc, curr) => acc + curr.valueInUsd,
832
+ 0
833
+ );
834
+ return {
835
+ totalRebalances,
836
+ totalRebalanceVolume,
837
+ rebalances
838
+ };
839
+ };
840
+ var getRebalanceStats = async (getClient, {
841
+ includeTestnet = false,
842
+ account
843
+ }) => {
844
+ const chains = getChainsForEnv({ includeTestnet });
845
+ const rebalances = await Promise.all(
846
+ chains.map(async (chain) => {
847
+ const rawRebalances = await fetchChainRebalances(chain.chainId);
848
+ const client = getClient(chain.chainId);
849
+ return processRebalancesInBatches(
850
+ rawRebalances,
851
+ chain.chainId,
852
+ client,
853
+ account
854
+ );
855
+ })
856
+ );
857
+ const allRebalances = rebalances.flat();
858
+ return calculateRebalanceStats(allRebalances);
859
+ };
860
+ export {
861
+ calculateRebalanceStats,
862
+ fetchChainRebalances,
863
+ getChainAutopools,
864
+ getChainAutopoolsApr,
865
+ getDefillamaPrice,
866
+ getEthPriceAtBlock,
867
+ getGenStratAprs,
868
+ getPoolsAndDestinations,
869
+ getRebalanceStats,
870
+ getTokenPrice
871
+ };