-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathutils.ts
More file actions
157 lines (135 loc) · 4.67 KB
/
utils.ts
File metadata and controls
157 lines (135 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { mapSupportedNetworks, SupportedChainId } from '@cowprotocol/cow-sdk'
import assert from 'assert'
import fs from 'fs'
import winston, { Logger } from 'winston'
export interface TokenInfo {
chainId: SupportedChainId
address: string
name: string
symbol: string
decimals: number
logoURI?: string
volume?: number
}
export type Overrides = Record<string, Partial<TokenInfo> | null>
export type OverridesPerChain = Record<SupportedChainId, Overrides>
interface CoingeckoToken {
id: string
platforms: {
[chain: string]: string
}
}
export type CoingeckoIdsMap = Record<string, Record<string, string>>
export const COINGECKO_API_KEY = process.env.COINGECKO_API_KEY
assert(COINGECKO_API_KEY, 'COINGECKO_API_KEY env is required')
export const COINGECKO_CHAINS: Record<SupportedChainId, string | null> = {
[SupportedChainId.MAINNET]: 'ethereum',
[SupportedChainId.GNOSIS_CHAIN]: 'xdai',
[SupportedChainId.BASE]: 'base',
[SupportedChainId.ARBITRUM_ONE]: 'arbitrum-one',
[SupportedChainId.SEPOLIA]: null,
[SupportedChainId.POLYGON]: 'polygon-pos',
[SupportedChainId.AVALANCHE]: 'avalanche',
[SupportedChainId.BNB]: 'binance-smart-chain',
[SupportedChainId.LINEA]: 'linea',
[SupportedChainId.PLASMA]: 'plasma',
[SupportedChainId.INK]: 'ink',
}
export const DISPLAY_CHAIN_NAMES: Record<SupportedChainId, string | null> = {
[SupportedChainId.MAINNET]: 'Ethereum',
[SupportedChainId.GNOSIS_CHAIN]: 'Gnosis chain',
[SupportedChainId.BASE]: 'Base',
[SupportedChainId.ARBITRUM_ONE]: 'Arbitrum one',
[SupportedChainId.SEPOLIA]: null,
[SupportedChainId.POLYGON]: 'Polygon',
[SupportedChainId.AVALANCHE]: 'Avalanche',
[SupportedChainId.BNB]: 'BNB',
[SupportedChainId.LINEA]: 'Linea',
[SupportedChainId.PLASMA]: 'Plasma',
[SupportedChainId.INK]: 'Ink',
}
export const VS_CURRENCY = 'usd'
export const TOP_TOKENS_COUNT = 500
const COINGECKO_CHAINS_NAMES = Object.values(COINGECKO_CHAINS)
const TOKEN_LISTS_CACHE: Record<SupportedChainId, TokenInfo[]> = mapSupportedNetworks(() => [])
export async function fetchWithApiKey(url: string): Promise<any> {
try {
const headers = COINGECKO_API_KEY ? { 'X-Cg-Pro-Api-Key': COINGECKO_API_KEY } : undefined
const response = await fetch(url, { headers })
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
console.log(`Fetched from ${url}:`, response.status)
const data = await response.json()
console.log(`Data from ${url}:`, data)
return data
} catch (error) {
console.error(`Failed to fetch from ${url}:`, error)
throw error
}
}
async function getCoingeckoTokenIds(): Promise<CoingeckoToken[]> {
try {
return await fetchWithApiKey('https://pro-api.coingecko.com/api/v3/coins/list?include_platform=true&status=active')
} catch (error) {
console.error(`Error fetching Coingecko's coin list:`, error)
return []
}
}
export async function getCoingeckoTokenIdsMap(): Promise<CoingeckoIdsMap> {
const tokenIdsMap = COINGECKO_CHAINS_NAMES.reduce<CoingeckoIdsMap>(
(acc, name) => (name ? { ...acc, [name]: {} } : acc),
{},
)
try {
const tokenIds = await getCoingeckoTokenIds()
tokenIds.forEach((token) => {
COINGECKO_CHAINS_NAMES.forEach((chain) => {
if (!chain) return
const address = token.platforms[chain]?.toLowerCase()
if (address) {
tokenIdsMap[chain][address] = token.id
tokenIdsMap[chain][token.id] = address // reverse mapping
}
})
})
return tokenIdsMap
} catch (error) {
console.error(`Error building Coingecko token IDs map:`, error)
return tokenIdsMap
}
}
function getTokenListUrl(chain: SupportedChainId): string {
return `https://tokens.coingecko.com/${COINGECKO_CHAINS[chain]}/all.json`
}
export async function getTokenList(chain: SupportedChainId): Promise<TokenInfo[]> {
if (TOKEN_LISTS_CACHE[chain].length) {
return TOKEN_LISTS_CACHE[chain]
}
const data = await fetchWithApiKey(getTokenListUrl(chain))
TOKEN_LISTS_CACHE[chain] = data.tokens
return data.tokens
}
export function removeOldLogs(context: string): void {
const logFiles = [`${context}.log`, `${context}-error.log`]
logFiles.forEach((file) => {
if (fs.existsSync(file)) {
fs.unlinkSync(file)
}
})
}
let logger: Logger
export function getLogger(context: string): Logger {
if (!logger) {
logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: `${context}.log` }),
new winston.transports.File({ filename: `${context}-error.log`, level: 'error' }),
new winston.transports.Console({ level: 'error' }),
],
})
}
return logger
}