@defillama/sdk 5.0.235 → 5.0.238
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/build/ChainApi.d.ts +23 -1
- package/build/ChainApi.js +13 -0
- package/build/abi/tron.js +7 -1
- package/build/chains/algorand.d.ts +277 -0
- package/build/chains/algorand.js +618 -0
- package/build/chains/aptos.d.ts +230 -0
- package/build/chains/aptos.js +612 -0
- package/build/chains/cardano.d.ts +242 -0
- package/build/chains/cardano.js +407 -0
- package/build/chains/cosmos.d.ts +252 -0
- package/build/chains/cosmos.js +618 -0
- package/build/chains/icp.d.ts +235 -0
- package/build/chains/icp.js +1040 -0
- package/build/chains/index.d.ts +23 -0
- package/build/chains/index.js +59 -0
- package/build/chains/near.d.ts +192 -0
- package/build/chains/near.js +446 -0
- package/build/chains/rpc.d.ts +125 -0
- package/build/chains/rpc.js +326 -0
- package/build/chains/starknet.d.ts +205 -0
- package/build/chains/starknet.js +884 -0
- package/build/chains/stellar.d.ts +410 -0
- package/build/chains/stellar.js +1082 -0
- package/build/chains/substrate.d.ts +333 -0
- package/build/chains/substrate.js +1042 -0
- package/build/chains/sui.d.ts +365 -0
- package/build/chains/sui.js +1135 -0
- package/build/chains/svm.d.ts +340 -0
- package/build/chains/svm.js +760 -0
- package/build/chains/tezos.d.ts +225 -0
- package/build/chains/tezos.js +412 -0
- package/build/chains/ton.d.ts +353 -0
- package/build/chains/ton.js +788 -0
- package/build/chains/tron.d.ts +45 -0
- package/build/chains/tron.js +110 -0
- package/build/chains/utxo.d.ts +202 -0
- package/build/chains/utxo.js +592 -0
- package/build/chains/xrpl.d.ts +179 -0
- package/build/chains/xrpl.js +467 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +3 -1
- package/build/providers.json +1 -1
- package/build/util/LlamaProvider.js +2 -0
- package/build/util/blocks.js +292 -84
- package/build/util/chainUtils/data.json +80 -0
- package/build/util/chainUtils/index.d.ts +1 -0
- package/build/util/chainUtils/index.js +23 -0
- package/build/util/coins.js +14 -3
- package/build/util/common.js +6 -4
- package/build/util/computeTVL.js +1 -1
- package/build/util/cosmos.d.ts +1 -11
- package/build/util/cosmos.js +6 -66
- package/build/util/env.d.ts +1 -0
- package/build/util/env.js +18 -0
- package/build/util/indexer.compatibility.d.ts +6 -0
- package/build/util/indexer.compatibility.js +64 -0
- package/build/util/indexer.d.ts +24 -2
- package/build/util/indexer.js +333 -294
- package/build/util/indexerSql.d.ts +8 -1
- package/build/util/indexerSql.js +53 -22
- package/build/util/logs.d.ts +3 -0
- package/build/util/logs.decode.shared.js +5 -4
- package/build/util/logs.js +57 -26
- package/build/util/transactions.d.ts +23 -1
- package/build/util/updateChainLabels.d.ts +1 -0
- package/build/util/updateChainLabels.js +5 -0
- package/build/util/updateProviderList.js +40 -18
- package/package.json +20 -7
- package/README.md +0 -41
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
export type IndexerSqlOptions = {
|
|
2
|
+
/** Accepted for compatibility with dimension-adapters; all chains use the same gateway. */
|
|
3
|
+
chain?: string;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
};
|
|
1
6
|
export declare function isIndexerSqlEnabled(): boolean;
|
|
2
|
-
export declare function queryClickhouse<T = any>(sql: string, params?: Record<string, unknown>, settings?: Record<string, string | number
|
|
7
|
+
export declare function queryClickhouse<T = any>(sql: string, params?: Record<string, unknown>, settings?: Record<string, string | number>, options?: IndexerSqlOptions): Promise<T[]>;
|
|
8
|
+
/** Gateway-oriented name; queryClickhouse remains available for existing consumers. */
|
|
9
|
+
export declare const queryIndexerSql: typeof queryClickhouse;
|
package/build/util/indexerSql.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.queryIndexerSql = void 0;
|
|
6
7
|
exports.isIndexerSqlEnabled = isIndexerSqlEnabled;
|
|
7
8
|
exports.queryClickhouse = queryClickhouse;
|
|
8
9
|
const axios_1 = __importDefault(require("axios"));
|
|
@@ -11,40 +12,76 @@ const https_1 = __importDefault(require("https"));
|
|
|
11
12
|
const env_1 = require("./env");
|
|
12
13
|
const httpAgent = new http_1.default.Agent({ keepAlive: true, maxSockets: 64, maxFreeSockets: 16 });
|
|
13
14
|
const httpsAgent = new https_1.default.Agent({ keepAlive: true, maxSockets: 64, maxFreeSockets: 16 });
|
|
14
|
-
function
|
|
15
|
+
function getSqlConfig() {
|
|
16
|
+
const v4Endpoint = (0, env_1.getEnvValue)("LLAMA_INDEXER_V4_ENDPOINT");
|
|
15
17
|
return {
|
|
16
|
-
endpoint: (0, env_1.getEnvValue)("LLAMA_INDEXER_SQL_ENDPOINT"),
|
|
18
|
+
endpoint: (0, env_1.getEnvValue)("LLAMA_INDEXER_SQL_ENDPOINT") || (v4Endpoint ? `${v4Endpoint.replace(/\/+$/, "")}/sql` : undefined),
|
|
17
19
|
user: (0, env_1.getEnvValue)("LLAMA_INDEXER_SQL_USER"),
|
|
18
20
|
password: (0, env_1.getEnvValue)("LLAMA_INDEXER_SQL_PASSWORD"),
|
|
19
|
-
timeoutMs: +(0, env_1.getEnvValue)("LLAMA_INDEXER_SQL_TIMEOUT_MS") || 180000,
|
|
20
21
|
};
|
|
21
22
|
}
|
|
23
|
+
// ClickHouse HTTP query parameters use escaped text, not JSON. Nested strings
|
|
24
|
+
// must be quoted, and UInt64/UInt256 values must never pass through Number().
|
|
25
|
+
function serializeQueryParameter(value, nested = false) {
|
|
26
|
+
if (value === null || value === undefined)
|
|
27
|
+
return nested ? "NULL" : "\\N";
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")
|
|
30
|
+
.replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
31
|
+
return nested ? `'${escaped}'` : escaped;
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === "boolean")
|
|
34
|
+
return nested ? (value ? "TRUE" : "FALSE") : (value ? "1" : "0");
|
|
35
|
+
if (typeof value === "number") {
|
|
36
|
+
if (Number.isNaN(value))
|
|
37
|
+
return "nan";
|
|
38
|
+
if (!Number.isFinite(value))
|
|
39
|
+
return value > 0 ? "+inf" : "-inf";
|
|
40
|
+
return String(value);
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === "bigint")
|
|
43
|
+
return String(value);
|
|
44
|
+
if (Array.isArray(value))
|
|
45
|
+
return `[${value.map((v) => serializeQueryParameter(v, true)).join(",")}]`;
|
|
46
|
+
if (value instanceof Date) {
|
|
47
|
+
const seconds = String(Math.floor(value.getTime() / 1000)).padStart(10, "0");
|
|
48
|
+
return value.getUTCMilliseconds() ? `${seconds}.${String(value.getUTCMilliseconds()).padStart(3, "0")}` : seconds;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === "object") {
|
|
51
|
+
const entries = value instanceof Map ? [...value.entries()] : Object.entries(value);
|
|
52
|
+
return `{${entries.map(([k, v]) => `${serializeQueryParameter(k, true)}:${serializeQueryParameter(v, true)}`).join(",")}}`;
|
|
53
|
+
}
|
|
54
|
+
throw new Error("Unsupported SQL query parameter type");
|
|
55
|
+
}
|
|
22
56
|
function isIndexerSqlEnabled() {
|
|
23
|
-
const c =
|
|
57
|
+
const c = getSqlConfig();
|
|
24
58
|
return !!(c.endpoint && c.user && c.password);
|
|
25
59
|
}
|
|
26
|
-
async function queryClickhouse(sql, params, settings) {
|
|
60
|
+
async function queryClickhouse(sql, params, settings, options = {}) {
|
|
27
61
|
var _a, _b;
|
|
28
|
-
const { endpoint, user, password
|
|
62
|
+
const { endpoint, user, password } = getSqlConfig();
|
|
29
63
|
if (!endpoint || !user || !password) {
|
|
30
64
|
throw new Error("Llama indexer SQL gateway not configured (LLAMA_INDEXER_SQL_ENDPOINT/USER/PASSWORD)");
|
|
31
65
|
}
|
|
32
|
-
const
|
|
66
|
+
const url = new URL(endpoint);
|
|
67
|
+
const search = url.searchParams;
|
|
33
68
|
search.set("default_format", "JSONEachRow");
|
|
34
|
-
for (const [
|
|
35
|
-
search.set(`param_${
|
|
69
|
+
for (const [name, value] of Object.entries(params !== null && params !== void 0 ? params : {})) {
|
|
70
|
+
search.set(`param_${name}`, serializeQueryParameter(value));
|
|
36
71
|
}
|
|
37
|
-
for (const [
|
|
38
|
-
search.set(
|
|
72
|
+
for (const [name, value] of Object.entries(settings !== null && settings !== void 0 ? settings : {})) {
|
|
73
|
+
search.set(name, String(value));
|
|
39
74
|
}
|
|
40
75
|
let res;
|
|
41
76
|
try {
|
|
42
|
-
res = await axios_1.default.post(
|
|
77
|
+
res = await axios_1.default.post(url.toString(), sql, {
|
|
43
78
|
auth: { username: user, password },
|
|
44
79
|
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
45
80
|
responseType: "text",
|
|
46
81
|
transformResponse: (d) => d,
|
|
47
|
-
|
|
82
|
+
// The gateway owns execution deadlines. Callers can still cancel a request.
|
|
83
|
+
timeout: 0,
|
|
84
|
+
signal: options.signal,
|
|
48
85
|
maxBodyLength: Infinity,
|
|
49
86
|
maxContentLength: Infinity,
|
|
50
87
|
httpAgent,
|
|
@@ -59,13 +96,7 @@ async function queryClickhouse(sql, params, settings) {
|
|
|
59
96
|
return parseJsonEachRow(res.data);
|
|
60
97
|
}
|
|
61
98
|
function parseJsonEachRow(text) {
|
|
62
|
-
|
|
63
|
-
return [];
|
|
64
|
-
const out = [];
|
|
65
|
-
for (const line of text.split("\n")) {
|
|
66
|
-
if (!line)
|
|
67
|
-
continue;
|
|
68
|
-
out.push(JSON.parse(line));
|
|
69
|
-
}
|
|
70
|
-
return out;
|
|
99
|
+
return text.split("\n").filter(line => line.trim()).map(line => JSON.parse(line));
|
|
71
100
|
}
|
|
101
|
+
/** Gateway-oriented name; queryClickhouse remains available for existing consumers. */
|
|
102
|
+
exports.queryIndexerSql = queryClickhouse;
|
package/build/util/logs.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventLog, Interface } from "ethers";
|
|
2
2
|
import { Address } from "../types";
|
|
3
3
|
import { IndexerGetLogsOptions } from "./indexer";
|
|
4
|
+
export declare function getBufferedToBlock(toBlock: number, head?: number, buffer?: number): number;
|
|
4
5
|
export type GetLogsOptions = {
|
|
5
6
|
target?: Address;
|
|
6
7
|
topic?: string;
|
|
@@ -30,6 +31,8 @@ export type GetLogsOptions = {
|
|
|
30
31
|
allowParseFailure?: boolean;
|
|
31
32
|
};
|
|
32
33
|
export declare function getLogs(options: GetLogsOptions): Promise<EventLog[] | EventLog[][] | any[]>;
|
|
34
|
+
export declare function maxLogsForStorage(bytesPerLog: number, cap?: number, budgetMB?: number): number;
|
|
35
|
+
export declare function trimCachesForStorage(caches: logCache[], maxLogs?: number): logCache[];
|
|
33
36
|
export declare function toFilterTopic(topic: string): string;
|
|
34
37
|
export type logCache = {
|
|
35
38
|
logs: EventLog[];
|
|
@@ -19,11 +19,12 @@ function padTopic32(t) {
|
|
|
19
19
|
return ('0x' + hex.padStart(64, '0'));
|
|
20
20
|
}
|
|
21
21
|
function normalizeLog(log, isIndexerCall = false) {
|
|
22
|
+
var _a, _b, _c, _d;
|
|
22
23
|
if (isIndexerCall || log.source) {
|
|
23
|
-
log.address = log.source;
|
|
24
|
-
log.logIndex = log.log_index;
|
|
25
|
-
log.index = log.
|
|
26
|
-
log.transactionHash = log.transaction_hash;
|
|
24
|
+
log.address = (_a = log.source) !== null && _a !== void 0 ? _a : log.address;
|
|
25
|
+
log.logIndex = (_c = (_b = log.log_index) !== null && _b !== void 0 ? _b : log.logIndex) !== null && _c !== void 0 ? _c : log.index;
|
|
26
|
+
log.index = log.logIndex;
|
|
27
|
+
log.transactionHash = (_d = log.transaction_hash) !== null && _d !== void 0 ? _d : log.transactionHash;
|
|
27
28
|
log.blockNumber = parseInt(log.block_number || log.blockNumber || 0);
|
|
28
29
|
const topics = [log.topic0, log.topic1, log.topic2, log.topic3]
|
|
29
30
|
.filter(Boolean)
|
package/build/util/logs.js
CHANGED
|
@@ -3,7 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getBufferedToBlock = getBufferedToBlock;
|
|
6
7
|
exports.getLogs = getLogs;
|
|
8
|
+
exports.maxLogsForStorage = maxLogsForStorage;
|
|
9
|
+
exports.trimCachesForStorage = trimCachesForStorage;
|
|
7
10
|
exports.toFilterTopic = toFilterTopic;
|
|
8
11
|
exports.getLogParams = getLogParams;
|
|
9
12
|
const ethers_1 = require("ethers");
|
|
@@ -17,6 +20,15 @@ const env_1 = require("./env");
|
|
|
17
20
|
const common_1 = require("./common");
|
|
18
21
|
const logs_decode_shared_1 = require("./logs.decode.shared");
|
|
19
22
|
const currentVersion = "v3";
|
|
23
|
+
const BLOCK_BUFFER = 10;
|
|
24
|
+
// widen the fetched range forward by BLOCK_BUFFER, without asking for blocks the chain does not
|
|
25
|
+
// have yet and without ever returning less than the caller asked for
|
|
26
|
+
function getBufferedToBlock(toBlock, head, buffer = BLOCK_BUFFER) {
|
|
27
|
+
const buffered = toBlock + buffer;
|
|
28
|
+
if (head === undefined)
|
|
29
|
+
return buffered;
|
|
30
|
+
return Math.min(buffered, Math.max(toBlock, head));
|
|
31
|
+
}
|
|
20
32
|
/* -------------------------------------------------------------------------- */
|
|
21
33
|
/* getLogs */
|
|
22
34
|
/* -------------------------------------------------------------------------- */
|
|
@@ -133,8 +145,16 @@ async function getLogs(options) {
|
|
|
133
145
|
(0, debugLog_1.debugLog)("adding logs to cache:", fromBlock, toBlock);
|
|
134
146
|
if (fromBlock > toBlock)
|
|
135
147
|
return;
|
|
136
|
-
fromBlock = Math.max(fromBlock -
|
|
137
|
-
|
|
148
|
+
fromBlock = Math.max(fromBlock - BLOCK_BUFFER, 0); // avoid negative block
|
|
149
|
+
// the forward buffer must not run past the chain head. Several RPCs reject a range that ends
|
|
150
|
+
// beyond their latest block outright, and since every RPC in the pool rejects it the whole call
|
|
151
|
+
// fails. If the head cannot be read (halted chain, provider error) keep the previous behaviour.
|
|
152
|
+
let head;
|
|
153
|
+
try {
|
|
154
|
+
head = await (0, blocks_1.getBlockNumber)(chain);
|
|
155
|
+
}
|
|
156
|
+
catch (e) { }
|
|
157
|
+
toBlock = getBufferedToBlock(toBlock, head);
|
|
138
158
|
if (debugMode)
|
|
139
159
|
console.time(dbgKey);
|
|
140
160
|
const { output: newLogs } = await (0, _1.getLogs)({
|
|
@@ -156,8 +176,8 @@ async function getLogs(options) {
|
|
|
156
176
|
const merged = [caches[0]];
|
|
157
177
|
caches.slice(1).forEach((c) => {
|
|
158
178
|
const last = merged[merged.length - 1];
|
|
159
|
-
if (last.metadata.toBlock + 1
|
|
160
|
-
last.metadata.toBlock = c.metadata.toBlock;
|
|
179
|
+
if (last.metadata.toBlock + 1 >= c.metadata.fromBlock) {
|
|
180
|
+
last.metadata.toBlock = Math.max(last.metadata.toBlock, c.metadata.toBlock);
|
|
161
181
|
last.logs = dedupLogs(last.logs, c.logs);
|
|
162
182
|
}
|
|
163
183
|
else
|
|
@@ -174,28 +194,9 @@ async function getLogs(options) {
|
|
|
174
194
|
}, 0);
|
|
175
195
|
const fileSizeInMB = (totalLogCount * randomLogLength) / (1024 * 1024);
|
|
176
196
|
if (fileSizeInMB > 300) { // if cache size is larger than ~300MB, trim it down
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
let cacheWithLatestFromBlock = caches[0];
|
|
181
|
-
for (const c of caches) {
|
|
182
|
-
if (c.metadata.fromBlock > cacheWithLatestFromBlock.metadata.fromBlock) {
|
|
183
|
-
cacheWithLatestFromBlock = c;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
storeCaches = [cacheWithLatestFromBlock];
|
|
187
|
-
}
|
|
188
|
-
storeCaches = storeCaches.map(c => {
|
|
189
|
-
const clone = { logs: [], metadata: JSON.parse(JSON.stringify(c.metadata)) };
|
|
190
|
-
if (c.logs.length > 200000) {
|
|
191
|
-
// sort the logs by block number descending and keep only the latest 200k logs
|
|
192
|
-
c.logs.sort((a, b) => b.blockNumber - a.blockNumber);
|
|
193
|
-
clone.logs = c.logs.slice(0, 200000);
|
|
194
|
-
const lastLog = clone.logs[clone.logs.length - 1];
|
|
195
|
-
clone.metadata.fromBlock = lastLog.blockNumber;
|
|
196
|
-
}
|
|
197
|
-
return clone;
|
|
198
|
-
});
|
|
197
|
+
const maxLogs = maxLogsForStorage(randomLogLength);
|
|
198
|
+
console.log(`getLogs: large cache size detected ${totalLogCount} logs size: ${fileSizeInMB}MB, retaining only the latest ${maxLogs} logs to limit memory usage target=${target} topic=${topic} fromBlock=${fromBlock} toBlock=${toBlock}`);
|
|
199
|
+
storeCaches = trimCachesForStorage(storeCaches, maxLogs);
|
|
199
200
|
}
|
|
200
201
|
// we are skipping compression by default, so reads & writes are faster
|
|
201
202
|
await (0, cache_1.writeCache)(getFile(), { caches: storeCaches, version: currentVersion }, { skipR2CacheWrite: !cacheInCloud, skipCompression: !cacheInCloud });
|
|
@@ -246,6 +247,36 @@ async function getLogs(options) {
|
|
|
246
247
|
/* -------------------------------------------------------------------------- */
|
|
247
248
|
/* Utility helpers exported */
|
|
248
249
|
/* -------------------------------------------------------------------------- */
|
|
250
|
+
// the log count that fits the same byte budget the size check uses, so a wide log trims before the flat cap
|
|
251
|
+
function maxLogsForStorage(bytesPerLog, cap = 200000, budgetMB = 300) {
|
|
252
|
+
if (!bytesPerLog || bytesPerLog < 1)
|
|
253
|
+
return cap;
|
|
254
|
+
return Math.max(1, Math.min(cap, Math.floor((budgetMB * 1024 * 1024) / bytesPerLog)));
|
|
255
|
+
}
|
|
256
|
+
// keeps the newest range and at most maxLogs of its logs, narrowing the metadata to match what is kept
|
|
257
|
+
function trimCachesForStorage(caches, maxLogs = 200000) {
|
|
258
|
+
if (!caches.length)
|
|
259
|
+
return caches;
|
|
260
|
+
let trimmed = caches;
|
|
261
|
+
if (caches.length > 1) {
|
|
262
|
+
let cacheWithLatestFromBlock = caches[0];
|
|
263
|
+
for (const c of caches) {
|
|
264
|
+
if (c.metadata.fromBlock > cacheWithLatestFromBlock.metadata.fromBlock) {
|
|
265
|
+
cacheWithLatestFromBlock = c;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
trimmed = [cacheWithLatestFromBlock];
|
|
269
|
+
}
|
|
270
|
+
return trimmed.map(c => {
|
|
271
|
+
const clone = { logs: c.logs, metadata: JSON.parse(JSON.stringify(c.metadata)) };
|
|
272
|
+
if (c.logs.length > maxLogs) {
|
|
273
|
+
const sorted = [...c.logs].sort((a, b) => b.blockNumber - a.blockNumber);
|
|
274
|
+
clone.logs = sorted.slice(0, maxLogs);
|
|
275
|
+
clone.metadata.fromBlock = clone.logs[clone.logs.length - 1].blockNumber;
|
|
276
|
+
}
|
|
277
|
+
return clone;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
249
280
|
function toFilterTopic(topic) {
|
|
250
281
|
if (topic.startsWith("0x"))
|
|
251
282
|
return topic;
|
|
@@ -10,4 +10,26 @@ export interface GetTransactionOptions {
|
|
|
10
10
|
debugMode?: boolean;
|
|
11
11
|
transactionType?: 'from' | 'to' | 'all';
|
|
12
12
|
}
|
|
13
|
-
export declare function getTransactions(params: GetTransactionOptions): Promise<
|
|
13
|
+
export declare function getTransactions(params: GetTransactionOptions): Promise<{
|
|
14
|
+
hash: any;
|
|
15
|
+
blockNumber: number;
|
|
16
|
+
transactionIndex: number;
|
|
17
|
+
from: any;
|
|
18
|
+
to: any;
|
|
19
|
+
value: any;
|
|
20
|
+
gasPrice: any;
|
|
21
|
+
gas: any;
|
|
22
|
+
input: any;
|
|
23
|
+
nonce: number;
|
|
24
|
+
data: any;
|
|
25
|
+
type: any;
|
|
26
|
+
maxFeePerGas: any;
|
|
27
|
+
maxPriorityFeePerGas: any;
|
|
28
|
+
baseFeePerGas: any;
|
|
29
|
+
effectiveGasPrice: any;
|
|
30
|
+
gasUsed: any;
|
|
31
|
+
cumulativeGasUsed: any;
|
|
32
|
+
status: number;
|
|
33
|
+
contractCreated: any;
|
|
34
|
+
timestamp: any;
|
|
35
|
+
}[] | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chainUtils_1 = require("./chainUtils");
|
|
4
|
+
// pulls latest chain key <-> label mappings and dead chain list from the llama api and writes them to chainUtils/data.json
|
|
5
|
+
(0, chainUtils_1.updateChainLabels)();
|
|
@@ -29,27 +29,19 @@ async function getChainData() {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
async function main() {
|
|
32
|
-
|
|
33
|
-
const chainLabelsKeyMapCountBefore = Object.keys(chainUtils_1.chainLabelsToKeyMap).length;
|
|
34
|
-
await (0, chainUtils_1.updateData)();
|
|
35
|
-
const chainKeyLabelMapCountAfter = Object.keys(chainUtils_1.chainKeyToChainLabelMap).length;
|
|
36
|
-
const chainLabelsKeyMapCountAfter = Object.keys(chainUtils_1.chainLabelsToKeyMap).length;
|
|
37
|
-
if (chainKeyLabelMapCountAfter > chainKeyLabelMapCountBefore) {
|
|
38
|
-
console.log(`Updated chainKeyToChainLabelMap: ${chainKeyLabelMapCountBefore} -> ${chainKeyLabelMapCountAfter}`);
|
|
39
|
-
}
|
|
40
|
-
if (chainLabelsKeyMapCountAfter > chainLabelsKeyMapCountBefore) {
|
|
41
|
-
console.log(`Updated chainLabelsToKeyMap: ${chainLabelsKeyMapCountBefore} -> ${chainLabelsKeyMapCountAfter}`);
|
|
42
|
-
}
|
|
43
|
-
if (chainKeyLabelMapCountAfter < chainKeyLabelMapCountBefore)
|
|
44
|
-
throw new Error('chainKeyToChainLabelMap count decreased, please investigate');
|
|
45
|
-
if (chainLabelsKeyMapCountAfter < chainLabelsKeyMapCountBefore)
|
|
46
|
-
throw new Error('chainLabelsToKeyMap count decreased, please investigate');
|
|
32
|
+
await (0, chainUtils_1.updateChainLabels)();
|
|
47
33
|
const oldProviders = await (0, generalUtil_1.fetchJson)(`https://unpkg.com/@defillama/sdk@latest/build/providers.json`);
|
|
48
34
|
const currentChains = await (0, generalUtil_1.fetchJson)(`https://raw.githubusercontent.com/DefiLlama/DefiLlama-Adapters/refs/heads/main/projects/helper/chains.json`);
|
|
49
35
|
const currentChainsSet = new Set(currentChains);
|
|
50
36
|
let chainData = await getChainData();
|
|
51
37
|
const providerIDMap = {};
|
|
52
|
-
|
|
38
|
+
const chainIdToKeyMap = {};
|
|
39
|
+
Object.entries(providerList).forEach(([key, i]) => {
|
|
40
|
+
providerIDMap[i.chainId] = i.rpc;
|
|
41
|
+
chainIdToKeyMap[i.chainId] = key;
|
|
42
|
+
});
|
|
43
|
+
const shortNameToKeyMap = {};
|
|
44
|
+
Object.entries(chainShortNameMapping).forEach(([key, shortName]) => shortNameToKeyMap[shortName] = key);
|
|
53
45
|
chainData = chainData
|
|
54
46
|
.filter((i) => i.rpc.length)
|
|
55
47
|
// .filter((i: any) => !i.status || (i.status === 'active' || i.status === 'incubating'))
|
|
@@ -93,12 +85,39 @@ async function main() {
|
|
|
93
85
|
});
|
|
94
86
|
// shuffle the array
|
|
95
87
|
chainData.sort(() => Math.random() - 0.5);
|
|
88
|
+
// chain keys this chain could end up under in providers.json
|
|
89
|
+
const getCandidateKeys = (i) => {
|
|
90
|
+
const keys = [i.shortName.toLowerCase().replace(/-/g, '_')];
|
|
91
|
+
if (chainIdToKeyMap[i.chainId])
|
|
92
|
+
keys.push(chainIdToKeyMap[i.chainId]);
|
|
93
|
+
if (shortNameToKeyMap[i.shortName])
|
|
94
|
+
keys.push(shortNameToKeyMap[i.shortName]);
|
|
95
|
+
return keys;
|
|
96
|
+
};
|
|
97
|
+
// only check rpc health for chains we track and that are not dead, the rest are only filtered statically
|
|
98
|
+
const shouldCheckRPCs = (i) => {
|
|
99
|
+
const keys = getCandidateKeys(i);
|
|
100
|
+
const isTracked = keys.some((k) => currentChainsSet.has(k));
|
|
101
|
+
const isDead = keys.some((k) => (0, chainUtils_1.isDeadChain)(k));
|
|
102
|
+
return isTracked && !isDead;
|
|
103
|
+
};
|
|
104
|
+
const skippedRPCChecks = { dead: 0, untracked: 0 };
|
|
96
105
|
await promise_pool_1.default
|
|
97
106
|
.withConcurrency(concurrentCheckChains)
|
|
98
107
|
.for(chainData)
|
|
99
108
|
.process(async (i) => {
|
|
100
109
|
var _a, _b;
|
|
101
|
-
|
|
110
|
+
const rpcs = i.rpc.map((j) => j.url);
|
|
111
|
+
if (shouldCheckRPCs(i)) {
|
|
112
|
+
i.rpc = await filterForWorkingRPCs(rpcs, i.name, i.chainId);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (getCandidateKeys(i).some((k) => (0, chainUtils_1.isDeadChain)(k)))
|
|
116
|
+
skippedRPCChecks.dead++;
|
|
117
|
+
else
|
|
118
|
+
skippedRPCChecks.untracked++;
|
|
119
|
+
i.rpc = rpcs.length < 4 ? rpcs : filterRPCs(rpcs);
|
|
120
|
+
}
|
|
102
121
|
if (!i.rpc.length)
|
|
103
122
|
return;
|
|
104
123
|
if (providerIDMap[i.chainId]) {
|
|
@@ -158,6 +177,8 @@ async function main() {
|
|
|
158
177
|
const rpcCountOld = Object.values(oldProviders).reduce((acc, i) => { var _a; return acc + ((_a = i === null || i === void 0 ? void 0 : i.rpc.length) !== null && _a !== void 0 ? _a : 0); }, 0);
|
|
159
178
|
const newlyAddedChains = Object.keys(providerList).filter(chain => oldProviders[chain] === undefined);
|
|
160
179
|
console.log('Final provider list:');
|
|
180
|
+
console.log('Skipped rpc checks (dead chains):', skippedRPCChecks.dead);
|
|
181
|
+
console.log('Skipped rpc checks (untracked chains):', skippedRPCChecks.untracked);
|
|
161
182
|
console.log('Chain count:', Object.keys(providerList).length);
|
|
162
183
|
console.log('Newly added chains count:', newlyAddedChains.length);
|
|
163
184
|
console.log('Dropped chain count:', filteredDroppedChains.length);
|
|
@@ -238,7 +259,8 @@ async function filterForWorkingRPCs(rpc, chain, chainId) {
|
|
|
238
259
|
if (data.result) {
|
|
239
260
|
const returnedChainId = parseInt(data.result, 16);
|
|
240
261
|
if (returnedChainId !== chainId) {
|
|
241
|
-
console.log(`RPC ${i} for ${chain} returned invalid chainId ${returnedChainId}, expected ${chainId}`);
|
|
262
|
+
console.log(`RPC ${i} for ${chain} returned invalid chainId ${returnedChainId}, expected ${chainId}, skipping`);
|
|
263
|
+
return;
|
|
242
264
|
}
|
|
243
265
|
filteredRPCs.push(i);
|
|
244
266
|
}
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defillama/sdk",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.238",
|
|
4
4
|
"description": "SDK for calculating TVL",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "npm run build && node build/index.js",
|
|
8
8
|
"pack-and-publish": "bash ./scripts/skipTestPatchAndPublish.sh",
|
|
9
9
|
"build": "tsc",
|
|
10
|
-
"watch": "tsc --watch",
|
|
11
10
|
"load-providers": "mkdir -p build && wget https://unpkg.com/@defillama/sdk@latest/build/providers.json -O build/providers.json",
|
|
12
11
|
"test": "npm run load-providers && TEST_MODE=true LLAMA_DEBUG_MODE='' SDK_DEBUG='' LLAMA_DEBUG_LEVEL2='' LLAMA_DEBUG_LEVEL3='' jest",
|
|
13
12
|
"test-only": "echo 'skipped building providers.json' && TEST_MODE=true LLAMA_DEBUG_MODE='' SDK_DEBUG='' LLAMA_DEBUG_LEVEL2='' LLAMA_DEBUG_LEVEL3='' jest",
|
|
14
|
-
"test-debug": "TEST_MODE=true jest",
|
|
15
|
-
"test-indexer": "
|
|
13
|
+
"test-debug": "TEST_MODE=true JEST_VERBOSE=true jest",
|
|
14
|
+
"test-indexer": "jest --runInBand --runTestsByPath src/util/indexer.test.ts src/util/indexer.partialSync.test.ts src/util/indexer.partialSync.e2e.test.ts src/util/indexer.e2e.test.ts src/util/indexerSql.test.ts src/util/indexerSql.parity.test.ts",
|
|
15
|
+
"test-indexer-unit": "jest --runInBand --runTestsByPath src/util/indexer.test.ts src/util/indexer.partialSync.test.ts src/util/indexerSql.test.ts",
|
|
16
16
|
"update-providers": "ts-node src/util/updateProviderList.ts",
|
|
17
|
+
"update-chain-labels": "ts-node src/util/updateChainLabels.ts",
|
|
17
18
|
"remove-rpcs": "ts-node src/util/removeRedundantRPCs.ts",
|
|
18
|
-
"format": "prettier --write \"src/**/*.ts\"",
|
|
19
19
|
"prepublishOnly": "npm run build"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
@@ -23,10 +23,14 @@
|
|
|
23
23
|
"url": "git+https://github.com/DefiLlama/defillama-sdk.git"
|
|
24
24
|
},
|
|
25
25
|
"author": "",
|
|
26
|
-
"license": "ISC",
|
|
27
26
|
"types": "build/index.d.ts",
|
|
28
27
|
"files": [
|
|
29
|
-
"build"
|
|
28
|
+
"build",
|
|
29
|
+
"!build/**/*.test.js",
|
|
30
|
+
"!build/abi/largeMulticall.d.ts",
|
|
31
|
+
"!build/abi/largeMulticall.js",
|
|
32
|
+
"!build/**/*.test.d.ts",
|
|
33
|
+
"!build/**/*.test.js.map"
|
|
30
34
|
],
|
|
31
35
|
"dependencies": {
|
|
32
36
|
"@aws-sdk/client-s3": "^3.400.0",
|
|
@@ -39,8 +43,17 @@
|
|
|
39
43
|
"tron-format-address": "^0.1.11",
|
|
40
44
|
"viem": "^2.38.6"
|
|
41
45
|
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@solana/web3.js": ">=1.73.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@solana/web3.js": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
42
54
|
"devDependencies": {
|
|
43
55
|
"@types/jest": "^29.2.3",
|
|
56
|
+
"@types/node": "^24.8.1",
|
|
44
57
|
"@types/stream-json": "^1.7.8",
|
|
45
58
|
"jest": "^29.3.1",
|
|
46
59
|
"ts-jest": "^29.1.1",
|
package/README.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# sdk
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
npm i
|
|
5
|
-
npm run build
|
|
6
|
-
npm t
|
|
7
|
-
npm run format
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
### Publish
|
|
11
|
-
```
|
|
12
|
-
bash patchAndPublish.sh
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### Keys
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
POLYGON_RPC="https://..."
|
|
19
|
-
ETHEREUM_RPC="https://..."
|
|
20
|
-
BSC_RPC="https://..."
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Environment variables
|
|
24
|
-
|
|
25
|
-
Most settings can be overridden per chain via environment variables. The chain
|
|
26
|
-
name is uppercased and used as a prefix, e.g. `ETHEREUM_RPC`, `BSC_RPC_MULTICALL_V3`.
|
|
27
|
-
Every key is also resolved with an `SDK_` or `LLAMA_SDK_` prefix (checked in the
|
|
28
|
-
order `LLAMA_SDK_<KEY>` → `SDK_<KEY>` → `<KEY>`), so `SDK_ETHEREUM_RPC` works too.
|
|
29
|
-
|
|
30
|
-
| Variable | Description |
|
|
31
|
-
| --- | --- |
|
|
32
|
-
| `<CHAIN>_RPC` | RPC URL(s) for the chain (comma-separated for multiple). |
|
|
33
|
-
| `<CHAIN>_RPC_MULTICALL_V3` | Address of a Multicall3 contract for the chain. Setting it enables the Multicall3 code path for that chain (even if the chain is not in the built-in registry) and uses this address. Takes precedence over the built-in registry and the deployment-block gating. |
|
|
34
|
-
| `<CHAIN>_RPC_MULTICALL` | Address of a legacy (v2) multicall contract, used only when Multicall3 is not available for the chain. |
|
|
35
|
-
| `<CHAIN>_MULTICALL_CHUNK_SIZE` | Max number of calls per multicall batch for the chain. |
|
|
36
|
-
|
|
37
|
-
## Chain RPC PR
|
|
38
|
-
|
|
39
|
-
Before putting up a PR for new chain, check if we already support it here: https://unpkg.com/@defillama/sdk@latest/build/providers.json
|
|
40
|
-
|
|
41
|
-
Everytime we publish a new sdk version, we automically pull latest list from chainlist.org and include it.
|