-
Notifications
You must be signed in to change notification settings - Fork 50
/
tokenSymbolResolver.js
59 lines (50 loc) · 2.44 KB
/
tokenSymbolResolver.js
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
// service responsible for resolving symbols to ethereum addresses
const rp = require('request-promise')
const { COINGECKO_API_URL, AIRSWAP_TOKEN_METADATA_URL } = require('./constants.js')
const jsonTokensBySymbol = require('./tokensBySymbol.json')
// Returns a promise that will always resolve()
// will resolve with a string `tokenAddress` or `undefined`
// e.g. tokenSymbolResolver('DAI') -> "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
// tokenSymbolResolver('FizzBuzz') -> undefined
const tokenSymbolResolver = async symbol => {
let tokenAddress = null
try {
// first, query coingecko api and try to resolve dynamically
tokenAddress = await new Promise(async (resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('5s timeout reached waiting for Coingecko API'))
}, 5000)
try {
// get all tokens and find by relevant symbol
const cgTokensList = JSON.parse(await rp(`${COINGECKO_API_URL}/coins/list`))
const matchedTokens = cgTokensList.filter(tokenObj => tokenObj.symbol.toUpperCase() === symbol.toUpperCase())
if (matchedTokens.length === 0) throw new Error(`${symbol} not found in coingecko api`)
// it's possible there could be multiple tokens that match the symbol
// so we will return the one with the highest market cap between the group
const bestTokenMetadataMatch = (await Promise.all(
matchedTokens.map(obj => rp(`${COINGECKO_API_URL}/coins/${obj.id}`)),
))
.map(JSON.parse)
.reduce((a, b) => (a.market_cap_rank > b.market_cap_rank ? b : a))
if (!bestTokenMetadataMatch.contract_address) throw new Error(`${symbol} not found in coingecko api`)
// get decimals using airswap api
const { decimals } = JSON.parse(
await rp(`${AIRSWAP_TOKEN_METADATA_URL}/crawlTokenData?address=${bestTokenMetadataMatch.contract_address}`),
)
// resolve with token address and decimals
resolve({ addr: bestTokenMetadataMatch.contract_address, decimals: parseInt(decimals, 10) })
} catch (e) {
reject(e)
} finally {
// clean up event loop
global.clearTimeout(timeout)
}
})
} catch (e) {
console.log('error while resolving symbol with CoinGecko API:', e.message)
console.log('falling back to static token metadata')
tokenAddress = jsonTokensBySymbol[symbol]
}
return tokenAddress
}
module.exports = { tokenSymbolResolver }