|
|
@ -1,55 +1,113 @@ |
|
|
|
const log = require('loglevel') |
|
|
|
const log = require('loglevel') |
|
|
|
const util = require('./util') |
|
|
|
const util = require('./util') |
|
|
|
const BigNumber = require('bignumber.js') |
|
|
|
const BigNumber = require('bignumber.js') |
|
|
|
|
|
|
|
import contractMap from 'eth-contract-metadata' |
|
|
|
|
|
|
|
|
|
|
|
function tokenInfoGetter () { |
|
|
|
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => { |
|
|
|
const tokens = {} |
|
|
|
return { |
|
|
|
|
|
|
|
...acc, |
|
|
|
|
|
|
|
[base.toLowerCase()]: contractMap[base], |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, {}) |
|
|
|
|
|
|
|
|
|
|
|
return async (address) => { |
|
|
|
const DEFAULT_SYMBOL = '' |
|
|
|
if (tokens[address]) { |
|
|
|
const DEFAULT_DECIMALS = '0' |
|
|
|
return tokens[address] |
|
|
|
|
|
|
|
|
|
|
|
async function getSymbolFromContract (tokenAddress) { |
|
|
|
|
|
|
|
const token = util.getContractAtAddress(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
const result = await token.symbol() |
|
|
|
|
|
|
|
return result[0] |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
log.warn(`symbol() call for token at address ${tokenAddress} resulted in error:`, error) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getDecimalsFromContract (tokenAddress) { |
|
|
|
|
|
|
|
const token = util.getContractAtAddress(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
const result = await token.decimals() |
|
|
|
|
|
|
|
const decimalsBN = result[0] |
|
|
|
|
|
|
|
return decimalsBN && decimalsBN.toString() |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
log.warn(`decimals() call for token at address ${tokenAddress} resulted in error:`, error) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getContractMetadata (tokenAddress) { |
|
|
|
|
|
|
|
return tokenAddress && casedContractMap[tokenAddress.toLowerCase()] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getSymbol (tokenAddress) { |
|
|
|
|
|
|
|
let symbol = await getSymbolFromContract(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!symbol) { |
|
|
|
|
|
|
|
const contractMetadataInfo = getContractMetadata(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (contractMetadataInfo) { |
|
|
|
|
|
|
|
symbol = contractMetadataInfo.symbol |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tokens[address] = await getSymbolAndDecimals(address) |
|
|
|
return symbol |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return tokens[address] |
|
|
|
async function getDecimals (tokenAddress) { |
|
|
|
|
|
|
|
let decimals = await getDecimalsFromContract(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!decimals || decimals === '0') { |
|
|
|
|
|
|
|
const contractMetadataInfo = getContractMetadata(tokenAddress) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (contractMetadataInfo) { |
|
|
|
|
|
|
|
decimals = contractMetadataInfo.decimals |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return decimals |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { |
|
|
|
export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { |
|
|
|
const existingToken = existingTokens.find(({ address }) => tokenAddress === address) |
|
|
|
const existingToken = existingTokens.find(({ address }) => tokenAddress === address) |
|
|
|
|
|
|
|
|
|
|
|
if (existingToken) { |
|
|
|
if (existingToken) { |
|
|
|
return existingToken |
|
|
|
return { |
|
|
|
|
|
|
|
symbol: existingToken.symbol, |
|
|
|
|
|
|
|
decimals: existingToken.decimals, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let result = [] |
|
|
|
let symbol, decimals |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
const token = util.getContractAtAddress(tokenAddress) |
|
|
|
symbol = await getSymbol(tokenAddress) |
|
|
|
|
|
|
|
decimals = await getDecimals(tokenAddress) |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
log.warn(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, error) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result = await Promise.all([ |
|
|
|
return { |
|
|
|
token.symbol(), |
|
|
|
symbol: symbol || DEFAULT_SYMBOL, |
|
|
|
token.decimals(), |
|
|
|
decimals: decimals || DEFAULT_DECIMALS, |
|
|
|
]) |
|
|
|
|
|
|
|
} catch (err) { |
|
|
|
|
|
|
|
log.warn(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function tokenInfoGetter () { |
|
|
|
|
|
|
|
const tokens = {} |
|
|
|
|
|
|
|
|
|
|
|
const [ symbol = [], decimals = [] ] = result |
|
|
|
return async (address) => { |
|
|
|
|
|
|
|
if (tokens[address]) { |
|
|
|
|
|
|
|
return tokens[address] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
tokens[address] = await getSymbolAndDecimals(address) |
|
|
|
symbol: symbol[0] || null, |
|
|
|
|
|
|
|
decimals: decimals[0] && decimals[0].toString() || null, |
|
|
|
return tokens[address] |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function calcTokenAmount (value, decimals) { |
|
|
|
export function calcTokenAmount (value, decimals) { |
|
|
|
const multiplier = Math.pow(10, Number(decimals || 0)) |
|
|
|
const multiplier = Math.pow(10, Number(decimals || 0)) |
|
|
|
return new BigNumber(String(value)).div(multiplier).toNumber() |
|
|
|
return new BigNumber(String(value)).div(multiplier).toNumber() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = { |
|
|
|
|
|
|
|
tokenInfoGetter, |
|
|
|
|
|
|
|
calcTokenAmount, |
|
|
|
|
|
|
|
getSymbolAndDecimals, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|