Skip to content

Commit e5a3a19

Browse files
authored
V2 Chain Assets (#10820)
* pending ES allTokens, SDK price+mcap fetchers, error handling, remove WIP work * error logging, ES alltokens pending * L2 allToken ES * cached fetches * coins sdk integration * patch own tokens, tron, sol, totals * v2 in job
1 parent 3378ad1 commit e5a3a19

File tree

14 files changed

+328
-408
lines changed

14 files changed

+328
-408
lines changed

defi/l2/adapters/ada.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import fetch from "node-fetch";
1+
import { cache } from "@defillama/sdk";
22

33
export async function fetchAdaTokens(): Promise<any[]> {
4-
const res = await fetch(`https://api.muesliswap.com/token-list`).then((r) => r.json());
4+
const res = await cache.cachedFetch({key: "muesliswap-token-list", endpoint: "https://api.muesliswap.com/token-list"})
55
const coins = res
66
.filter((c: any) => c.supply.circulating != null)
77
.map((c: any) => ({

defi/l2/adapters/index.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,19 @@ export const starknet = async (): Promise<Address[]> => {
131131
addresses.starknet = data.map((t: any) => t.l2_token_address?.toLowerCase()).filter((t: any) => t != null);
132132
return addresses.starknet;
133133
};
134-
export const era = async (): Promise<Address[]> => {
135-
if (addresses.era) return addresses.era;
136-
const {
137-
data: { result: data },
138-
} = await axios.post("https://mainnet.era.zksync.io", {
139-
method: "zks_getConfirmedTokens",
140-
params: [0, 255],
141-
id: 1,
142-
jsonrpc: "2.0",
143-
});
144-
addresses.era = data.map((d: any) => d.l2Address.toLowerCase());
145-
return addresses.era;
146-
};
134+
// export const era = async (): Promise<Address[]> => {
135+
// if (addresses.era) return addresses.era;
136+
// const {
137+
// data: { result: data },
138+
// } = await axios.post("https://mainnet.era.zksync.io", {
139+
// method: "zks_getConfirmedTokens",
140+
// params: [0, 255],
141+
// id: 1,
142+
// jsonrpc: "2.0",
143+
// });
144+
// addresses.era = data.map((d: any) => d.l2Address.toLowerCase());
145+
// return addresses.era;
146+
// };
147147
export const tron = async (): Promise<Address[]> => {
148148
if (!("tron" in addresses)) addresses.tron = [];
149149
addresses.tron.push(
@@ -177,19 +177,19 @@ export const mode = async (): Promise<Address[]> => {
177177
);
178178
return addresses.mode;
179179
};
180-
export const zklink = async (): Promise<Address[]> => {
181-
if (addresses.zklink) return addresses.zklink;
182-
const allTokens = [];
183-
let page = 1;
184-
do {
185-
const { items, meta } = await fetch(`https://explorer-api.zklink.io/tokens?limit=200&page=${page}&key=`);
186-
allTokens.push(...items);
187-
page++;
188-
if (page >= meta.totalPages) break;
189-
} while (page < 100);
190-
addresses.zklink = allTokens.map((d: any) => d.l2Address.toLowerCase());
191-
return addresses.zklink;
192-
};
180+
// export const zklink = async (): Promise<Address[]> => {
181+
// if (addresses.zklink) return addresses.zklink;
182+
// const allTokens = [];
183+
// let page = 1;
184+
// do {
185+
// const { items, meta } = await fetch(`https://explorer-api.zklink.io/tokens?limit=200&page=${page}&key=`);
186+
// allTokens.push(...items);
187+
// page++;
188+
// if (page >= meta.totalPages) break;
189+
// } while (page < 100);
190+
// addresses.zklink = allTokens.map((d: any) => d.l2Address.toLowerCase());
191+
// return addresses.zklink;
192+
// };
193193
export const manta = async (): Promise<Address[]> => {
194194
if (addresses.manta) return addresses.manta;
195195
const bridge = (

defi/l2/adapters/thirdParty.ts

Lines changed: 51 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ import providers from "@defillama/sdk/build/providers.json";
33
import { Address } from "@defillama/sdk/build/types";
44
import { allChainKeys } from "../constants";
55
import { bridgedTvlMixedCaseChains } from "../../src/utils/shared/constants";
6-
import fetch from "node-fetch";
76
import { additional, excluded } from "./manual";
8-
import axios from "axios";
9-
import PromisePool from "@supercharge/promise-pool";
7+
import _ from "lodash";
8+
import { cachedFetch } from "@defillama/sdk/build/util/cache";
9+
import runInPromisePool from "@defillama/sdk/build/util/promisePool";
1010

11-
let bridgePromises: { [bridge: string]: Promise<any> } = {};
1211
const addresses: { [chain: Chain]: Address[] } = {};
1312
allChainKeys.map((c: string) => (addresses[c] = []));
14-
let doneAdapters: string[] = [];
15-
let mappingDone: boolean = false;
1613

1714
const chainMap: { [chain: string]: string } = {
1815
binance: "bsc",
@@ -25,24 +22,18 @@ Object.keys(providers).map((c: string) => {
2522
});
2623

2724
const hyperlane = async (): Promise<void> => {
28-
const bridge = "hyperlane";
29-
if (doneAdapters.includes(bridge)) return;
30-
if (!(bridge in bridgePromises))
31-
bridgePromises[bridge] = fetch(
32-
"https://raw.githubusercontent.com/Eclipse-Laboratories-Inc/gist/refs/heads/main/hyperlane-assets.json"
33-
).then((r) => r.json());
34-
const data = await bridgePromises[bridge];
25+
const data = await cachedFetch({
26+
key: "hyperlane-assets",
27+
endpoint: "https://raw.githubusercontent.com/Eclipse-Laboratories-Inc/gist/refs/heads/main/hyperlane-assets.json",
28+
});
29+
if (Object.keys(data).length == 0) throw new Error("No data or cache found for hyperlane third party");
3530
if (!addresses.eclipse) addresses.eclipse = [];
3631
data.map(({ address }: any) => addresses.eclipse.push(address));
37-
doneAdapters.push(bridge);
3832
};
3933

4034
const axelar = async (): Promise<void> => {
41-
const bridge = "axelar";
42-
if (doneAdapters.includes(bridge)) return;
43-
if (!(bridge in bridgePromises))
44-
bridgePromises[bridge] = fetch("https://api.axelarscan.io/api/getAssets").then((r) => r.json());
45-
const data = await bridgePromises[bridge];
35+
const data = await cachedFetch({ key: "axelar-assets", endpoint: "https://api.axelarscan.io/api/getAssets" });
36+
if (Object.keys(data).length == 0) throw new Error("No data or cache found for axelar third party");
4637
data.map((token: any) => {
4738
if (!token.addresses) return;
4839
Object.keys(token.addresses).map((chain: string) => {
@@ -51,22 +42,18 @@ const axelar = async (): Promise<void> => {
5142
if (!allChainKeys.includes(normalizedChain)) return;
5243
if (!("address" in token.addresses[chain] && "symbol" in token.addresses[chain])) return;
5344
if (!token.addresses[chain].symbol.startsWith("axl")) return;
54-
addresses[normalizedChain].push(token.addresses[chain].address.toLowerCase());
45+
addresses[normalizedChain].push(token.addresses[chain].address);
5546
});
5647
});
57-
doneAdapters.push(bridge);
5848
};
5949

6050
const wormhole = async (): Promise<void> => {
61-
const bridge = "wormhole";
62-
63-
if (doneAdapters.includes(bridge)) return;
64-
if (!(bridge in bridgePromises))
65-
bridgePromises[bridge] = axios.get(
66-
"https://raw.githubusercontent.com/wormhole-foundation/wormhole-token-list/main/content/by_dest.csv"
67-
);
51+
const data = await cachedFetch({
52+
key: "wormhole-token-list",
53+
endpoint: "https://raw.githubusercontent.com/wormhole-foundation/wormhole-token-list/main/content/by_dest.csv",
54+
});
55+
if (data.length == 0) throw new Error("No data or cache found for wormhole third party");
6856

69-
const data = (await bridgePromises[bridge]).data;
7057
const chainMap: { [ticker: string]: string } = {
7158
sol: "solana",
7259
eth: "ethereum",
@@ -95,43 +82,40 @@ const wormhole = async (): Promise<void> => {
9582
if (!addresses[chain]) addresses[chain] = [];
9683
addresses[chain].push(rows[3]);
9784
});
98-
doneAdapters.push(bridge);
9985
};
10086

10187
const celer = async (): Promise<void> => {
102-
const bridge = "celer";
103-
if (doneAdapters.includes(bridge)) return;
104-
if (!(bridge in bridgePromises))
105-
bridgePromises[bridge] = fetch("https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll").then((r) => r.json());
106-
const data = await bridgePromises[bridge];
88+
const data = await cachedFetch({
89+
key: "celer-transfer-configs",
90+
endpoint: "https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll",
91+
});
92+
if (Object.keys(data).length == 0) throw new Error("No data or cache found for celer third party");
10793
data.pegged_pair_configs.map((pp: any) => {
10894
const chain = chainIdMap[pp.org_chain_id];
10995
let normalizedChain: string = chain;
11096
if (chain in chainMap) normalizedChain = chainMap[chain];
11197
if (!allChainKeys.includes(normalizedChain)) return;
11298
if (!addresses[normalizedChain]) addresses[normalizedChain] = [];
113-
addresses[normalizedChain].push(pp.pegged_token.token.address.toLowerCase());
99+
addresses[normalizedChain].push(pp.pegged_token.token.address);
114100
});
115-
doneAdapters.push(bridge);
116101
};
117102

118103
const layerzero = async (): Promise<void> => {
119-
const bridge = "layerzero";
120-
if (doneAdapters.includes(bridge)) return;
121-
if (!(bridge in bridgePromises)) {
122-
bridgePromises[bridge] = Promise.all([
123-
fetch(
124-
"https://gist.githubusercontent.com/vrtnd/02b1125edf1afe2baddbf1027157aa31/raw/5cab2009357b1acb8982e6a80e66b64ab7ea1251/mappings.json"
125-
).then((r) => r.json()),
126-
fetch("https://metadata.layerzero-api.com/v1/metadata").then((r) => r.json()),
127-
]);
128-
}
129-
const data = await bridgePromises[bridge];
104+
const data = await Promise.all([
105+
cachedFetch({
106+
key: "layerzero-mappings",
107+
endpoint:
108+
"https://gist.githubusercontent.com/vrtnd/02b1125edf1afe2baddbf1027157aa31/raw/5cab2009357b1acb8982e6a80e66b64ab7ea1251/mappings.json",
109+
}),
110+
cachedFetch({ key: "layerzero-metadata", endpoint: "https://metadata.layerzero-api.com/v1/metadata" }),
111+
]);
112+
if (data[0].length == 0 || Object.keys(data[1]).length == 0)
113+
throw new Error("No data or cache found for layerzero third party");
130114

131115
data[0].map(({ to }: any) => {
132116
const [chain, address] = to.split(":");
133117
if (!(chain in addresses)) addresses[chain] = [];
134-
if (!(address in addresses[chain])) addresses[chain].push(address.toLowerCase());
118+
if (!(address in addresses[chain])) addresses[chain].push(address);
135119
});
136120

137121
const nonEvmMapping: { [key: string]: string } = {
@@ -173,33 +157,24 @@ const layerzero = async (): Promise<void> => {
173157
if (!(chain in addresses)) addresses[chain] = [];
174158
addresses[chain].push(...staticTokens[chain]);
175159
});
176-
177-
doneAdapters.push(bridge);
178160
};
179161

180162
const flow = async (): Promise<void> => {
181-
const bridge = "flow";
182-
if (doneAdapters.includes(bridge)) return;
183-
if (!(bridge in bridgePromises))
184-
bridgePromises[bridge] = fetch(
185-
"https://raw.githubusercontent.com/onflow/assets/refs/heads/main/tokens/outputs/mainnet/token-list.json"
186-
).then((r) => r.json());
187-
const data = await bridgePromises[bridge];
163+
const data = await cachedFetch({
164+
key: "flow-token-list",
165+
endpoint: "https://raw.githubusercontent.com/onflow/assets/refs/heads/main/tokens/outputs/mainnet/token-list.json",
166+
});
167+
if (Object.keys(data).length == 0) throw new Error("No data or cache found for flow third party");
188168
data.tokens.map(({ chainId, address, tags }: any) => {
189169
const chain = chainIdMap[chainId];
190170
if (!allChainKeys.includes(chain)) return;
191171
if (!tags.includes("bridged-coin")) return;
192172
if (!(chain in addresses)) addresses[chain] = [];
193173
addresses[chain].push(address);
194174
});
195-
196-
doneAdapters.push(bridge);
197175
};
198176

199177
const unit = async (): Promise<void> => {
200-
const bridge = "unit";
201-
if (doneAdapters.includes(bridge)) return;
202-
203178
const staticTokens: { [chain: string]: string[] } = {
204179
hyperliquid: [
205180
"0x9FDBdA0A5e284c32744D2f17Ee5c74B284993463",
@@ -213,27 +188,23 @@ const unit = async (): Promise<void> => {
213188
if (!(chain in addresses)) addresses[chain] = [];
214189
addresses[chain].push(...staticTokens[chain]);
215190
});
216-
217-
doneAdapters.push(bridge);
218191
};
219192

220193
const adapters = { axelar, wormhole, celer, hyperlane, layerzero, flow, unit };
221194

222195
const filteredAddresses: { [chain: Chain]: Address[] } = {};
223196

224-
const tokenAddresses = async (): Promise<{ [chain: Chain]: Address[] }> => {
225-
await PromisePool.withConcurrency(5)
226-
.for(Object.entries(adapters))
227-
.process(async ([key, adapter]: any) => {
228-
try {
229-
await adapter();
230-
} catch (e: any) {
231-
throw new Error(`${key} fails with ${e.message}`);
232-
}
233-
});
234-
235-
if (Object.keys(adapters).length == doneAdapters.length && mappingDone) return filteredAddresses;
236-
197+
const tokenAddresses = _.once(async (): Promise<{ [chain: Chain]: Address[] }> => {
198+
await runInPromisePool({
199+
items: Object.entries(adapters),
200+
concurrency: 5,
201+
processor: async ([key, adapter]: any) => {
202+
await adapter().catch((e: any) => {
203+
throw new Error(`${key} fails with ${e.message}`);
204+
});
205+
}})
206+
207+
// remove excluded assets and add additional assets, normalize case
237208
Object.keys(addresses).map((chain: string) => {
238209
let chainAddresses =
239210
chain in excluded ? addresses[chain].filter((t: string) => !excluded[chain].includes(t)) : addresses[chain];
@@ -248,8 +219,7 @@ const tokenAddresses = async (): Promise<{ [chain: Chain]: Address[] }> => {
248219
filteredAddresses[chain] = [...new Set([...chainAddresses, ...additionalTokens])];
249220
});
250221

251-
mappingDone = true;
252222
return filteredAddresses;
253-
};
223+
});
254224

255-
export default tokenAddresses;
225+
export default tokenAddresses;

0 commit comments

Comments
 (0)