@defillama/sdk 5.0.179 → 5.0.182

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.
@@ -60,7 +60,7 @@ class LlamaProvider extends ethers_1.FallbackProvider {
60
60
  currentBlocks[url] = block;
61
61
  }
62
62
  catch (e) {
63
- if (env_1.logLlamaProviderCalls)
63
+ if (env_1.ENV_CONSTANTS.LOG_LLAMA_PROVIDER_CALLS)
64
64
  (0, debugLog_1.debugLog)(`${_this.chainName} skipping RPC ${url} is not working, error: ${e.message}`);
65
65
  _this._removeProvider(url);
66
66
  }
@@ -134,6 +134,9 @@ let lastBlockCacheSave = Date.now();
134
134
  const blockCacheSaveInterval = 1000 * 60 * 5; // 5 minutes
135
135
  const { data: blockTimeCache, saveCacheFile: saveBlockCacheFile } = (0, cache_1.getTempLocalCache)({ file: 'BlockCache.json', defaultData: {}, clearAfter: cache_1.ONE_WEEK, returnWithSaveFunction: true });
136
136
  function validateCurrentBlock(block, chain = 'ethereum') {
137
+ // sometimes the chain is halted or facing issues, so we skip the validation for those chains
138
+ if ((0, env_1.shouldSkipCurrentBlockValidation)(chain))
139
+ return;
137
140
  const provider = getExtraProvider(chain);
138
141
  const now = Math.floor(Date.now() / 1000);
139
142
  const minutesDiff = Math.floor((now - block.timestamp) / 60);
@@ -227,7 +230,7 @@ async function _lookupBlock(timestamp, extraParams) {
227
230
  ]);
228
231
  updateBlock(blocks);
229
232
  }
230
- if (i > 2 && env_1.logGetBlockStats)
233
+ if (i > 2 && env_1.ENV_CONSTANTS.GET_BLOCK_STATS)
231
234
  (0, debugLog_1.debugLog)(`chain: ${chain} block: ${block.number} #calls: ${i} imprecision: ${Number((imprecision) / 60).toFixed(2)} (min) Time Taken: ${Number((Date.now() - time) / 1000).toFixed(2)} (in sec)`);
232
235
  if (chain !== "bsc" && // this check is there because bsc halted the chain for few days
233
236
  Math.abs(block.timestamp - timestamp) > 3600) {
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.ONE_WEEK = exports.currentVersion = void 0;
7
4
  exports.readCache = readCache;
@@ -19,7 +16,6 @@ const zlib_1 = require("zlib");
19
16
  const util_1 = require("util");
20
17
  const env_1 = require("./env");
21
18
  const common_1 = require("./common");
22
- const crypto_1 = __importDefault(require("crypto"));
23
19
  const brotliOptions = {
24
20
  [zlib_1.constants.BROTLI_PARAM_MODE]: zlib_1.constants.BROTLI_MODE_TEXT,
25
21
  [zlib_1.constants.BROTLI_PARAM_QUALITY]: zlib_1.constants.BROTLI_MAX_QUALITY,
@@ -99,7 +95,7 @@ async function writeCache(file, data, options = {}) {
99
95
  (0, debugLog_1.debugLog)('Data too small to cache: ', file);
100
96
  return;
101
97
  }
102
- if (isSameData(data, await readCache(file, { skipR2Cache: true, skipCompression: options.skipCompression, })))
98
+ if (!options.skipCompression && isSameData(data, await readCache(file, { skipR2Cache: true, skipCompression: options.skipCompression, })))
103
99
  return;
104
100
  if (options.skipCompression)
105
101
  file = `${file}-uncompressed`;
@@ -241,7 +237,7 @@ async function cachedFetch({ key, endpoint, postData, fetcher, fetchOptions, err
241
237
  if (!key) {
242
238
  if (!endpoint || postData || fetcher)
243
239
  throw new Error('Key is required for cachedFetch');
244
- key = crypto_1.default.createHash('sha256').update(endpoint).digest('hex').substring(0, 32);
240
+ key = (0, common_1.getHash)(endpoint);
245
241
  }
246
242
  const fileKey = 'cached-fetch/' + key;
247
243
  try {
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getPrices = getPrices;
7
+ exports.getMcaps = getMcaps;
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const env_1 = require("./env");
10
+ const promisePool_1 = __importDefault(require("./promisePool"));
11
+ const common_1 = require("./common");
12
+ const _1 = require(".");
13
+ const coinsApiKey = (0, env_1.getEnvValue)("COINS_API_KEY");
14
+ const bodySize = 100;
15
+ function getBodies(readKeys, timestamp) {
16
+ const chunks = (0, _1.sliceIntoChunks)(readKeys, bodySize);
17
+ return chunks.map(chunk => {
18
+ const body = { coins: chunk };
19
+ if (timestamp !== "now")
20
+ body.timestamp = timestamp;
21
+ return body;
22
+ });
23
+ }
24
+ async function restCallWrapper(request, retries = 3, name = "-") {
25
+ retries--;
26
+ try {
27
+ const res = await request();
28
+ return res;
29
+ }
30
+ catch (e) {
31
+ if (retries <= 0)
32
+ throw (0, common_1.formError)(e);
33
+ }
34
+ await (0, common_1.sleepRandom)(5000 + 10000, 5000);
35
+ return restCallWrapper(request, retries, name);
36
+ }
37
+ const priceCacheAll = {
38
+ now: {
39
+ "coingecko:tether": {
40
+ price: 1,
41
+ symbol: "USDT",
42
+ timestamp: Math.floor(Date.now() / 1e3 + 3600), // an hour from script start time
43
+ },
44
+ }
45
+ };
46
+ const mcapCacheAll = {};
47
+ async function getPrices(readKeys, timestamp) {
48
+ return getPricesData(readKeys, timestamp, "price");
49
+ }
50
+ async function getPricesData(readKeys, timestamp, dataType) {
51
+ if (!readKeys.length)
52
+ return {};
53
+ const cacheAllObject = dataType === "price" ? priceCacheAll : mcapCacheAll;
54
+ const subRoute = dataType === "price" ? "prices" : "mcaps";
55
+ const aggregatedRes = {};
56
+ const timestampString = timestamp.toString();
57
+ const priceCache = cacheAllObject[timestampString] || {};
58
+ if (!cacheAllObject[timestampString])
59
+ cacheAllObject[timestampString] = priceCache;
60
+ // read data from cache where possible
61
+ readKeys = readKeys.filter((PK) => {
62
+ const pkNormalized = PK.toLowerCase();
63
+ let pkData = priceCache[pkNormalized];
64
+ if (pkData) {
65
+ aggregatedRes[PK] = { ...pkData, PK };
66
+ return false;
67
+ }
68
+ return true;
69
+ });
70
+ const bodies = getBodies(readKeys, timestamp);
71
+ await (0, promisePool_1.default)({
72
+ items: bodies,
73
+ concurrency: 10,
74
+ processor: async (body) => {
75
+ if (!body.coins.length)
76
+ return;
77
+ const res = await restCallWrapper(() => axios_1.default.post(`https://coins.llama.fi/${subRoute}`, body, {
78
+ headers: { "Content-Type": "application/json" },
79
+ params: { source: "internal", apikey: coinsApiKey },
80
+ }));
81
+ const data = dataType === "price" ? res.data.coins : res.data;
82
+ Object.entries(data).forEach(([PK, value]) => {
83
+ const pkNormalized = PK.toLowerCase();
84
+ priceCache[pkNormalized] = value;
85
+ });
86
+ body.coins.forEach((PK) => {
87
+ const pkNormalized = PK.toLowerCase();
88
+ const coinData = priceCache[pkNormalized];
89
+ if (coinData)
90
+ aggregatedRes[PK] = { ...coinData, PK };
91
+ });
92
+ },
93
+ });
94
+ return aggregatedRes;
95
+ }
96
+ async function getMcaps(readKeys, timestamp) {
97
+ return getPricesData(readKeys, timestamp, "mcap");
98
+ }
@@ -30,4 +30,5 @@ export declare function evmToTronAddress(address: string): string;
30
30
  export declare function sleep(ms: number): Promise<unknown>;
31
31
  export declare function sleepRandom(max: number, min?: number): Promise<unknown>;
32
32
  export declare function fixTronCallParams(params: any): void;
33
+ export declare function getHash(str: string | string[]): string;
33
34
  export {};
@@ -33,6 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  return result;
34
34
  };
35
35
  })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
36
39
  Object.defineProperty(exports, "__esModule", { value: true });
37
40
  exports.convertToBigInt = convertToBigInt;
38
41
  exports.sumMultiBalanceOf = sumMultiBalanceOf;
@@ -52,10 +55,12 @@ exports.evmToTronAddress = evmToTronAddress;
52
55
  exports.sleep = sleep;
53
56
  exports.sleepRandom = sleepRandom;
54
57
  exports.fixTronCallParams = fixTronCallParams;
58
+ exports.getHash = getHash;
55
59
  const axios_1 = __importStar(require("axios"));
56
60
  const ethers = __importStar(require("ethers"));
57
61
  const TronAddressFormatter = __importStar(require("tron-format-address"));
58
62
  const env_1 = require("./env");
63
+ const crypto_1 = __importDefault(require("crypto"));
59
64
  function convertToBigInt(value) {
60
65
  const balance = value;
61
66
  if (!value)
@@ -229,7 +234,7 @@ function formErrorString(e, errorParams = {}) {
229
234
  }
230
235
  if (e.llamaRPCError) {
231
236
  const errorString = `Llama RPC error! method: ${e.method} `;
232
- const errors = e.errors.map((i) => { var _a; return `- host: ${i === null || i === void 0 ? void 0 : i.host} error: ${(_a = i === null || i === void 0 ? void 0 : i.error) === null || _a === void 0 ? void 0 : _a.message}`; });
237
+ const errors = e.errors.map((i) => { var _a; return `- host: ${i === null || i === void 0 ? void 0 : i.host} error: ${typeof (i === null || i === void 0 ? void 0 : i.error) === 'string' ? i === null || i === void 0 ? void 0 : i.error : (_a = i === null || i === void 0 ? void 0 : i.error) === null || _a === void 0 ? void 0 : _a.message}`; });
233
238
  return errorString + '\n' + errors.join('\n');
234
239
  }
235
240
  let errorString = e.toString();
@@ -286,11 +291,20 @@ function formErrorString(e, errorParams = {}) {
286
291
  }
287
292
  return errorString;
288
293
  }
289
- function shortenString(str, length = env_1.defaultShortenStringLength) {
294
+ function shortenString(str, length) {
295
+ if (!length) {
296
+ if (!isNaN(+env_1.ENV_CONSTANTS.DEFAULT_SHORTEN_STRING_LENGTH))
297
+ length = +env_1.ENV_CONSTANTS.DEFAULT_SHORTEN_STRING_LENGTH;
298
+ if (!length || isNaN(length))
299
+ length = 120;
300
+ }
290
301
  return str.length > length ? str.slice(0, length).concat('...') : str;
291
302
  }
292
303
  function formError(e, errorParams = {}) {
293
304
  var _a;
305
+ if (e instanceof Error && (0, env_1.getBoolEnvValue)('DEBUG_ERROR_STACK')) {
306
+ console.error(e);
307
+ }
294
308
  const errorParamsSet = Object.keys(errorParams).length;
295
309
  if ((e === null || e === void 0 ? void 0 : e._isCustomError) || (!errorParamsSet && typeof e === 'object' && !Object.keys(e).length))
296
310
  return e; // already formatted or vannila error
@@ -350,3 +364,8 @@ function fixTronCallParams(params) {
350
364
  if (Array.isArray(params.calls))
351
365
  params.calls.forEach(fixTronCallParams);
352
366
  }
367
+ function getHash(str) {
368
+ if (Array.isArray(str))
369
+ str = str.join('-');
370
+ return crypto_1.default.createHash('sha256').update(str).digest('hex').substring(0, 32);
371
+ }
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = computeTVL;
4
4
  exports.getUnique = getUnique;
5
5
  const generalUtil_1 = require("../generalUtil");
6
- const coinsApi_1 = require("./coinsApi");
6
+ const coins_1 = require("./coins");
7
7
  const currentPriceCache = {};
8
8
  const priceCaches = {};
9
9
  let lastPriceUpdate = 0;
@@ -69,7 +69,7 @@ async function updatePriceCache(keys, timestamp) {
69
69
  "confidence": 1
70
70
  };
71
71
  const missingKeys = keys.filter(key => !pricesCache[key.toLowerCase()]);
72
- const coins = await (0, coinsApi_1.getPrices)(missingKeys, timestamp !== null && timestamp !== void 0 ? timestamp : "now");
72
+ const coins = await (0, coins_1.getPrices)(missingKeys, timestamp !== null && timestamp !== void 0 ? timestamp : "now");
73
73
  for (const [token, data] of Object.entries(coins)) {
74
74
  pricesCache[token.toLowerCase()] = data;
75
75
  }
@@ -1,12 +1,5 @@
1
- export declare const isDebugLevel3: boolean;
2
- export declare const logLlamaProviderCalls: boolean;
3
- export declare const logGetBlockStats: boolean;
4
- export declare const logGetLogsErrors: boolean;
5
- export declare const logGetLogsDebug: boolean;
6
- export declare const logGetLogsIndexer: boolean;
7
- export declare const defaultShortenStringLength: number;
8
1
  export declare const ENV_CONSTANTS: {
9
- [key: string]: string | undefined;
2
+ [key: string]: string | boolean | undefined;
10
3
  };
11
4
  export declare function getChainId(chain: string, chainId: number): number;
12
5
  export declare function getMaxParallelRequests(chain: string): number;
@@ -21,3 +14,5 @@ export declare function getBatchMaxCount(chain: string): number;
21
14
  export declare function getArchivalRPCs(chain: string): string[];
22
15
  export declare function getChainRPCs(chain: string, defaultList?: string[]): string | undefined;
23
16
  export declare function getWhitelistedRPCs(chain: string): string[];
17
+ export declare function shouldSkipCurrentBlockValidation(chain: string): boolean;
18
+ export declare function getBoolEnvValue(key: string, defaultValue?: boolean): boolean;
package/build/util/env.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.ENV_CONSTANTS = exports.defaultShortenStringLength = exports.logGetLogsIndexer = exports.logGetLogsDebug = exports.logGetLogsErrors = exports.logGetBlockStats = exports.logLlamaProviderCalls = exports.isDebugLevel3 = void 0;
4
+ exports.ENV_CONSTANTS = void 0;
5
5
  exports.getChainId = getChainId;
6
6
  exports.getMaxParallelRequests = getMaxParallelRequests;
7
7
  exports.getParallelGetLogsLimit = getParallelGetLogsLimit;
@@ -15,17 +15,13 @@ exports.getBatchMaxCount = getBatchMaxCount;
15
15
  exports.getArchivalRPCs = getArchivalRPCs;
16
16
  exports.getChainRPCs = getChainRPCs;
17
17
  exports.getWhitelistedRPCs = getWhitelistedRPCs;
18
+ exports.shouldSkipCurrentBlockValidation = shouldSkipCurrentBlockValidation;
19
+ exports.getBoolEnvValue = getBoolEnvValue;
18
20
  const whitelistedEnvConstants = [
19
21
  'R2_ENDPOINT', 'R2_ACCESS_KEY_ID', 'R2_SECRET_ACCESS_KEY', 'TRON_PRO_API_KEY', 'COINS_API_KEY',
20
22
  'ELASTICSEARCH_CONFIG', 'GRAPH_API_KEY', 'LLAMA_INDEXER_ENDPOINT', 'LLAMA_INDEXER_API_KEY', 'LLAMA_INDEXER_V2_ENDPOINT', 'LLAMA_INDEXER_V2_API_KEY',
21
23
  ];
22
- exports.isDebugLevel3 = process.env.LLAMA_SDK_DEBUG_LEVEL_3 === 'true' || false;
23
- exports.logLlamaProviderCalls = process.env.LLAMA_SDK_LOG_LLAMA_PROVIDER_CALLS === 'true' || exports.isDebugLevel3;
24
- exports.logGetBlockStats = process.env.LLAMA_SDK_LOG_GET_BLOCK_STATS === 'true' || exports.isDebugLevel3;
25
- exports.logGetLogsErrors = process.env.LLAMA_SDK_LOG_GET_LOGS_ERRORS === 'true' || exports.isDebugLevel3;
26
- exports.logGetLogsDebug = process.env.LLAMA_SDK_LOG_GET_LOGS_DEBUG === 'true' || exports.isDebugLevel3;
27
- exports.logGetLogsIndexer = process.env.LLAMA_SDK_LOG_GET_LOGS_INDEXER === 'true' || exports.isDebugLevel3;
28
- exports.defaultShortenStringLength = +((_a = process.env.LLAMA_SDK_DEFAULT_SHORTEN_STRING_LENGTH) !== null && _a !== void 0 ? _a : '120');
24
+ const isDebugLevel3 = process.env.LLAMA_SDK_DEBUG_LEVEL_3 === 'true';
29
25
  const defaultEnvValues = {
30
26
  INTERNAL_SDK_CACHE_FILE: './cache.json',
31
27
  TRON_RPC_CONCURRENCY_LIMIT: '5',
@@ -43,7 +39,15 @@ const defaultEnvValues = {
43
39
  };
44
40
  const _ENV_CONSTANTS = {
45
41
  DEBUG_ENABLED: getEnvValue('DEBUG') === "true" || process.env.LLAMA_DEBUG_MODE ? 'true' : 'false',
46
- DEBUG_LEVEL2: process.env.LLAMA_DEBUG_LEVEL2 ? 'true' : 'false',
42
+ DEBUG_ERROR_STACK: getEnvValue('DEBUG_ERROR_STACK') === "true",
43
+ DEBUG_LEVEL2: process.env.LLAMA_DEBUG_LEVEL2 || process.env.LLAMA_SDK_DEBUG_LEVEL_3 ? 'true' : 'false',
44
+ DEBUG_LEBEL_3: isDebugLevel3,
45
+ LOG_LLAMA_PROVIDER_CALLS: isDebugLevel3 || process.env.LLAMA_SDK_LOG_LLAMA_PROVIDER_CALLS === 'true',
46
+ GET_BLOCK_STATS: isDebugLevel3 || process.env.LLAMA_SDK_GET_BLOCK_STATS === 'true',
47
+ // GET_LOGS_ERRORS: isDebugLevel3 || process.env.LLAMA_SDK_GET_LOGS_ERRORS === 'true',
48
+ GET_LOGS_DEBUG: isDebugLevel3 || process.env.LLAMA_SDK_GET_LOGS_DEBUG === 'true',
49
+ GET_LOGS_INDEXER: isDebugLevel3 || process.env.LLAMA_SDK_GET_LOGS_INDEXER === 'true',
50
+ DEFAULT_SHORTEN_STRING_LENGTH: (_a = process.env.LLAMA_SDK_DEFAULT_SHORTEN_STRING_LENGTH) !== null && _a !== void 0 ? _a : '120',
47
51
  };
48
52
  whitelistedEnvConstants.forEach(key => _ENV_CONSTANTS[key] = getEnvValue(key));
49
53
  Object.keys(defaultEnvValues).forEach(key => _ENV_CONSTANTS[key] = getEnvValue(key, defaultEnvValues[key]));
@@ -130,3 +134,18 @@ function getWhitelistedRPCs(chain) {
130
134
  return getEnvValue(key).split(',');
131
135
  return [];
132
136
  }
137
+ let skipCurrentBlockValidationChainSet = null;
138
+ function shouldSkipCurrentBlockValidation(chain) {
139
+ if (!skipCurrentBlockValidationChainSet) {
140
+ const envValue = getEnvValue('SKIP_CURRENT_BLOCK_VALIDATION_CHAINS', '');
141
+ const chainList = envValue ? envValue.split(',').map(c => c.trim()) : [];
142
+ skipCurrentBlockValidationChainSet = new Set(chainList);
143
+ }
144
+ return skipCurrentBlockValidationChainSet.has(chain);
145
+ }
146
+ function getBoolEnvValue(key, defaultValue = false) {
147
+ const envValue = getEnvValue(key);
148
+ if (envValue === undefined)
149
+ return defaultValue;
150
+ return envValue === 'true';
151
+ }
@@ -55,7 +55,7 @@ async function getLogs(options) {
55
55
  catch (e) {
56
56
  options.provider = (0, general_1.getProvider)(options.chain, false);
57
57
  // if (provider === options.provider) throw e // the provider for archival and non-archival request is the same
58
- if (env_1.logGetLogsDebug)
58
+ if (env_1.ENV_CONSTANTS.GET_LOGS_DEBUG)
59
59
  (0, debugLog_1.debugLog)(`Error fetching logs for chain ${options.chain} ${(0, common_1.formError)(e, { chain: options.chain, target: options.target, })}, retrying...`);
60
60
  return getLimiter()(() => _getLogs(options));
61
61
  }
@@ -91,7 +91,7 @@ async function _getLogs(params) {
91
91
  currentBlock = nextBlock;
92
92
  }
93
93
  catch (e) {
94
- if (env_1.logGetLogsDebug)
94
+ if (env_1.ENV_CONSTANTS.GET_LOGS_DEBUG)
95
95
  (0, debugLog_1.debugLog)(`Error fetching logs for chain ${params.chain} blockSpread: ${blockSpread}. ${(0, common_1.formError)(e, { chain: params.chain, target: params.target, provider })}`);
96
96
  if (blockSpread >= 1001) {
97
97
  // We got too many results
@@ -160,7 +160,7 @@ async function getTokens(address, { onlyWhitelisted = true, skipCacheRead = fals
160
160
  if (cache.timestamp && timeNow - cache.timestamp < THREE_DAYS)
161
161
  return cache.tokens;
162
162
  }
163
- if (env_1.logGetLogsIndexer)
163
+ if (env_1.ENV_CONSTANTS.GET_LOGS_INDEXER)
164
164
  (0, debugLog_1.debugLog)("[Indexer] Pulling tokens for " + address);
165
165
  const tokens = (_b = cache.tokens) !== null && _b !== void 0 ? _b : {};
166
166
  const { data: { balances }, } = await axiosInstances.v1(`/balances`, {
@@ -197,7 +197,7 @@ async function getLogs(options) {
197
197
  let { all = true, limit = 1000, offset: initialOffset = 0, target, targets = [], flatten = true, debugMode = false, noTarget = false, maxBlockRange, processor, } = options;
198
198
  const { chain, fromBlock, toBlock, topic, topic1, topic2, topic3, transformLog, } = await (0, logs_1.getLogParams)(options, true);
199
199
  if (!debugMode)
200
- debugMode = debugLog_1.DEBUG_LEVEL2 && env_1.logGetLogsIndexer;
200
+ debugMode = debugLog_1.DEBUG_LEVEL2 && !!env_1.ENV_CONSTANTS.GET_LOGS_INDEXER;
201
201
  const blockRange = toBlock - fromBlock;
202
202
  const effectiveMaxBlockRange = maxBlockRange !== null && maxBlockRange !== void 0 ? maxBlockRange : (noTarget ? 10000 : Infinity);
203
203
  if (noTarget && blockRange > 500000) {
@@ -213,7 +213,7 @@ async function getLogs(options) {
213
213
  const percentageMissing = ((toBlock - lastIndexedBlock) / (toBlock - fromBlock)) * 100;
214
214
  if (percentageMissing > 50) // more than 50% of the requested range is missing, throw an error and so we pull the logs through rpc calls
215
215
  throw new Error(`Indexer not up to date for ${chain}. Last indexed block: ${lastIndexedBlock}, requested block: ${toBlock}`);
216
- if (env_1.logGetLogsIndexer)
216
+ if (env_1.ENV_CONSTANTS.GET_LOGS_INDEXER)
217
217
  (0, debugLog_1.debugLog)(`Indexer only partially up to date for ${chain}. Last indexed block: ${lastIndexedBlock}, requested block: ${toBlock}, missing ${Number(percentageMissing).toFixed(2)}%. Pulling part of the logs through RPC calls.`);
218
218
  // now we split the request into two parts, one that goes to the indexer and one that goes through rpc calls
219
219
  const breakBlock = lastIndexedBlock - 50; // we add a small buffer to avoid missing logs due to reorgs
@@ -329,7 +329,7 @@ async function getLogs(options) {
329
329
  async function getTokenTransfers({ chain = "ethereum", fromAddressFilter, fromBlock, toBlock, all = true, limit = 1000, offset = 0, target, targets = [], flatten = true, fromTimestamp, toTimestamp, debugMode = false, transferType = "in", token, tokens, }) {
330
330
  var _a, _b;
331
331
  if (!debugMode)
332
- debugMode = debugLog_1.DEBUG_LEVEL2 && env_1.logGetLogsIndexer;
332
+ debugMode = debugLog_1.DEBUG_LEVEL2 && !!env_1.ENV_CONSTANTS.GET_LOGS_INDEXER;
333
333
  checkIndexerConfig("v2");
334
334
  const chainId = getChainId(chain, "v2");
335
335
  // -----------------------------------------------------------------------
@@ -446,7 +446,7 @@ async function getTokenTransfers({ chain = "ethereum", fromAddressFilter, fromBl
446
446
  async function getTransactions({ chain = "ethereum", addresses, transaction_hashes, from_block, to_block, all = true, limit = 1000, offset = 0, debugMode = false, transactionType = "from", }) {
447
447
  var _a, _b;
448
448
  if (!debugMode)
449
- debugMode = debugLog_1.DEBUG_LEVEL2 && env_1.logGetLogsIndexer;
449
+ debugMode = debugLog_1.DEBUG_LEVEL2 && !!env_1.ENV_CONSTANTS.GET_LOGS_INDEXER;
450
450
  checkIndexerConfig("v2");
451
451
  const chainId = getChainId(chain, "v2");
452
452
  if ((!addresses || addresses.length === 0) && (!transaction_hashes || transaction_hashes.length === 0))
@@ -46,7 +46,7 @@ async function getLogs(options) {
46
46
  }
47
47
  }
48
48
  if (!debugMode)
49
- debugMode = debugLog_1.DEBUG_LEVEL2 && env_1.logGetLogsDebug;
49
+ debugMode = debugLog_1.DEBUG_LEVEL2 && !!env_1.ENV_CONSTANTS.GET_LOGS_DEBUG;
50
50
  /* ----------------------- Split by maxBlockRange ------------------------- */
51
51
  const blockRange = toBlock - fromBlock;
52
52
  if (maxBlockRange && blockRange > maxBlockRange) {
@@ -166,8 +166,42 @@ async function getLogs(options) {
166
166
  merged.push(c);
167
167
  });
168
168
  caches = merged;
169
- if (!skipCache) // we are skipping compression by default, so reads & writes are faster
170
- await (0, cache_1.writeCache)(getFile(), { caches, version: currentVersion }, { skipR2CacheWrite: !cacheInCloud, skipCompression: !cacheInCloud });
169
+ if (!skipCache) {
170
+ let storeCaches = caches;
171
+ let randomLogLength = 0;
172
+ const totalLogCount = caches.reduce((acc, c) => {
173
+ if (c.logs.length)
174
+ randomLogLength = JSON.stringify(c.logs[0]).length;
175
+ return acc + c.logs.length;
176
+ }, 0);
177
+ const fileSizeInMB = (totalLogCount * randomLogLength) / (1024 * 1024);
178
+ if (fileSizeInMB > 300) { // if cache size is larger than ~300MB, trim it down
179
+ console.log(`getLogs: large cache size detected ${totalLogCount} logs size: ${fileSizeInMB}MB, retaining only the latest 200k logs to limit memory usage target=${target} topic=${topic} fromBlock=${fromBlock} toBlock=${toBlock}`);
180
+ // retain only the latest logs that fit within 300,000 logs
181
+ if (caches.length > 1) {
182
+ let cacheWithLatestFromBlock = caches[0];
183
+ for (const c of caches) {
184
+ if (c.metadata.fromBlock > cacheWithLatestFromBlock.metadata.fromBlock) {
185
+ cacheWithLatestFromBlock = c;
186
+ }
187
+ }
188
+ storeCaches = [cacheWithLatestFromBlock];
189
+ }
190
+ storeCaches = storeCaches.map(c => {
191
+ const clone = { logs: [], metadata: JSON.parse(JSON.stringify(c.metadata)) };
192
+ if (c.logs.length > 200000) {
193
+ // sort the logs by block number descending and keep only the latest 200k logs
194
+ c.logs.sort((a, b) => b.blockNumber - a.blockNumber);
195
+ clone.logs = c.logs.slice(0, 200000);
196
+ const lastLog = clone.logs[clone.logs.length - 1];
197
+ clone.metadata.fromBlock = lastLog.blockNumber;
198
+ }
199
+ return clone;
200
+ });
201
+ }
202
+ // we are skipping compression by default, so reads & writes are faster
203
+ await (0, cache_1.writeCache)(getFile(), { caches: storeCaches, version: currentVersion }, { skipR2CacheWrite: !cacheInCloud, skipCompression: !cacheInCloud });
204
+ }
171
205
  }
172
206
  function dedupLogs(...arr) {
173
207
  const seen = new Set();
@@ -203,7 +237,12 @@ async function getLogs(options) {
203
237
  throw new Error("extraKey is required");
204
238
  if (keys.length)
205
239
  extraKey += "-" + keys.join("-").toLowerCase();
206
- return `event-logs/${chain}/${(_a = target === null || target === void 0 ? void 0 : target.toLowerCase()) !== null && _a !== void 0 ? _a : null}-${extraKey}`;
240
+ let file = `${(_a = target === null || target === void 0 ? void 0 : target.toLowerCase()) !== null && _a !== void 0 ? _a : null}-${extraKey}`;
241
+ const normalKeyLength = '0x27e5cb712334e101b3c232eb0be198baaa595f5f-0xe8137aa901976cc8eaf1cef5dec491873faadc99d9720ccaec95673294a9d7c5-uncompressed'.length;
242
+ // sometimes, there is a lot of topics and we hit the file name length limit
243
+ if (file.length > normalKeyLength)
244
+ file = (0, common_1.getHash)(file);
245
+ return `event-logs/${chain}/${file}`;
207
246
  }
208
247
  }
209
248
  /* -------------------------------------------------------------------------- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defillama/sdk",
3
- "version": "5.0.179",
3
+ "version": "5.0.182",
4
4
  "description": "SDK for calculating TVL",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -1,125 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getPrices = getPrices;
7
- exports.getMcaps = getMcaps;
8
- const axios_1 = __importDefault(require("axios"));
9
- const env_1 = require("./env");
10
- const promisePool_1 = __importDefault(require("./promisePool"));
11
- const common_1 = require("./common");
12
- const coinsApiKey = (0, env_1.getEnvValue)("COINS_API_KEY");
13
- const bodySize = 2; // 100;
14
- function getBodies(readKeys, timestamp) {
15
- const bodies = [];
16
- for (let i = 0; i < readKeys.length; i += bodySize) {
17
- const body = {
18
- coins: readKeys.slice(i, i + bodySize),
19
- };
20
- if (timestamp !== "now")
21
- body.timestamp = timestamp;
22
- bodies.push(JSON.stringify(body));
23
- }
24
- return bodies;
25
- }
26
- async function restCallWrapper(request, retries = 3, name = "-") {
27
- while (retries > 0) {
28
- try {
29
- const res = await request();
30
- return res;
31
- }
32
- catch {
33
- await (0, common_1.sleepRandom)(5000 + 10000, 5000);
34
- restCallWrapper(request, retries--, name);
35
- }
36
- }
37
- throw new Error(`couldnt work ${name} call after retries!`);
38
- }
39
- const priceCache = {
40
- "coingecko:tether": {
41
- price: 1,
42
- symbol: "USDT",
43
- timestamp: Math.floor(Date.now() / 1e3 + 3600), // an hour from script start time
44
- },
45
- };
46
- async function getPrices(readKeys, timestamp) {
47
- if (!readKeys.length)
48
- return {};
49
- const aggregatedRes = {};
50
- // read data from cache where possible
51
- readKeys = readKeys.filter((PK) => {
52
- if (timestamp !== "now")
53
- return true;
54
- if (priceCache[PK]) {
55
- aggregatedRes[PK] = { ...priceCache[PK], PK };
56
- return false;
57
- }
58
- return true;
59
- });
60
- const bodies = getBodies(readKeys, timestamp);
61
- const tokenData = [];
62
- await (0, promisePool_1.default)({
63
- items: bodies,
64
- concurrency: 10,
65
- processor: async (body) => {
66
- const res = await restCallWrapper(() => axios_1.default.post(`https://coins.llama.fi/prices?source=internal${coinsApiKey ? `?apikey=${coinsApiKey}` : ""}`, body, {
67
- headers: { "Content-Type": "application/json" },
68
- params: { source: "internal", apikey: coinsApiKey },
69
- }));
70
- const data = (res.data.coins = Object.entries(res.data.coins).map(([PK, value]) => ({
71
- ...value,
72
- PK,
73
- })));
74
- tokenData.push(data);
75
- },
76
- });
77
- const normalizedReadKeys = readKeys.map((k) => k.toLowerCase());
78
- tokenData.map((batch) => {
79
- batch.map((a) => {
80
- if (!a.PK)
81
- return;
82
- const i = normalizedReadKeys.indexOf(a.PK.toLowerCase());
83
- aggregatedRes[readKeys[i]] = a;
84
- });
85
- });
86
- return aggregatedRes;
87
- }
88
- const mcapCache = {};
89
- async function getMcaps(readKeys, timestamp) {
90
- if (!readKeys.length)
91
- return {};
92
- const aggregatedRes = {};
93
- // read data from cache where possible
94
- readKeys = readKeys.filter((PK) => {
95
- if (timestamp !== "now")
96
- return true;
97
- if (mcapCache[PK]) {
98
- aggregatedRes[PK] = { ...mcapCache[PK], PK };
99
- return false;
100
- }
101
- return true;
102
- });
103
- const bodies = getBodies(readKeys, timestamp);
104
- const tokenData = [];
105
- await (0, promisePool_1.default)({
106
- items: bodies,
107
- concurrency: 10,
108
- processor: async (body) => {
109
- const res = await restCallWrapper(() => axios_1.default.post(`https://coins.llama.fi/mcaps${coinsApiKey ? `?apikey=${coinsApiKey}` : ""}`, body, {
110
- headers: { "Content-Type": "application/json" },
111
- }));
112
- tokenData.push(res.data);
113
- },
114
- });
115
- const normalizedReadKeys = readKeys.map((k) => k.toLowerCase());
116
- tokenData.map((batch) => {
117
- Object.keys(batch).map((a) => {
118
- if (!batch[a].mcap)
119
- return;
120
- const i = normalizedReadKeys.indexOf(a.toLowerCase());
121
- aggregatedRes[readKeys[i]] = batch[a];
122
- });
123
- });
124
- return aggregatedRes;
125
- }
File without changes