Last active
November 21, 2018 19:42
-
-
Save destenson/69da2ddde8b97dae9a6622c6cb7e9ad5 to your computer and use it in GitHub Desktop.
Some random etherscan/uniswap code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const apiKeys = {etherscan:'GCGR1C9I17TYIRNYUDDEIJH1K5BRPH4UDE'} // EtherDelta's API key | |
const apiKey = (document.URL||'').includes('etherscan.io') ? 'YourApiKeyToken' : apiKeys.etherscan; | |
const uniswap = {factory:'0xc0a47dfe034b400b47bdad5fecda2621de6c4d95'}; | |
const factoryAddress = uniswap.factory; | |
function select(n) {return x => x[n]} | |
function addrId(a) {const x=4, y=3, z=2; return `${a.substr(z,x+z)}:${a.substr(a.length-y)}`} | |
function topicToAddr(n) {return logEvent => '0x'+logEvent.topics[n].substring(logEvent.topics[n].length-40)} | |
function topicToAddrId(n) {return addrId(topicToAddr(n))} | |
function savePromiseToLocalStorage(name) {return x => {x && localStorage.setItem(name, JSON.stringify(x)); return x}} | |
function parseBytesString(s) {const str=[];for(i=0; i<s.length; i+=2) {str.push(String.fromCharCode('0x'+s.substring(i,i+2)));} return str.join('')} | |
function chainPromises(promises=[]) { | |
return promises.reduce((chain, current) => | |
chain.then(results=>current.then(result=>[...results, result])), Promise.resolve([])) | |
} | |
function getCachedOr(name, f) { | |
return Promise.resolve(localStorage.getItem(name)) | |
.then(cached => {return cached ? JSON.parse(cached) : f().then(savePromiseToLocalStorage(name))}) | |
} | |
function getDelayed({ storageKey, fetchData }, force=false, waitMs=100) { | |
return force ? new Promise((resolve,reject) => { | |
setTimeout(forced=>{try {resolve(fetchData(forced));} catch(error) {reject(error);}}, waitMs) | |
}) | |
.catch(err=>{getDelayed({storageKey, fetchData}, false, waitMs*10).catch()}) | |
.then(savePromiseToLocalStorage(storageKey)) : | |
getCachedOr(storageKey, ()=>getDelayed({ storageKey, fetchData }, true, waitMs)) | |
} | |
const basicTokenInfo = web3.eth.contract([{"constant": true,"inputs": [],"name": "name","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "totalSupply","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "decimals","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [{"name": "","type": "address"}],"name": "balanceOf","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "symbol","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"}]); | |
const dsTokenContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name_","type":"bytes32"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"push","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"move","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"},{"name":"guy","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"wad","type":"uint256"}],"name":"pull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"symbol_","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]); | |
const exchangeContract = web3.eth.contract([{"name": "TokenPurchase", "inputs": [{"type": "address", "name": "buyer", "indexed": true}, {"type": "uint256", "name": "eth_sold", "indexed": true}, {"type": "uint256", "name": "tokens_bought", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "EthPurchase", "inputs": [{"type": "address", "name": "buyer", "indexed": true}, {"type": "uint256", "name": "tokens_sold", "indexed": true}, {"type": "uint256", "name": "eth_bought", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "AddLiquidity", "inputs": [{"type": "address", "name": "provider", "indexed": true}, {"type": "uint256", "name": "eth_amount", "indexed": true}, {"type": "uint256", "name": "token_amount", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "RemoveLiquidity", "inputs": [{"type": "address", "name": "provider", "indexed": true}, {"type": "uint256", "name": "eth_amount", "indexed": true}, {"type": "uint256", "name": "token_amount", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "Transfer", "inputs": [{"type": "address", "name": "_from", "indexed": true}, {"type": "address", "name": "_to", "indexed": true}, {"type": "uint256", "name": "_value", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "Approval", "inputs": [{"type": "address", "name": "_owner", "indexed": true}, {"type": "address", "name": "_spender", "indexed": true}, {"type": "uint256", "name": "_value", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "setup", "outputs": [], "inputs": [{"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 175875}, {"name": "addLiquidity", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_liquidity"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 82616}, {"name": "removeLiquidity", "outputs": [{"type": "uint256", "name": "out"}, {"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "amount"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 116814}, {"name": "__default__", "outputs": [], "inputs": [], "constant": false, "payable": true, "type": "function"}, {"name": "ethToTokenSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 12757}, {"name": "ethToTokenTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": true, "type": "function", "gas": 12965}, {"name": "ethToTokenSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 50463}, {"name": "ethToTokenTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": true, "type": "function", "gas": 50671}, {"name": "tokenToEthSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 47503}, {"name": "tokenToEthTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": false, "type": "function", "gas": 47712}, {"name": "tokenToEthSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 50175}, {"name": "tokenToEthTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": false, "type": "function", "gas": 50384}, {"name": "tokenToTokenSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 51007}, {"name": "tokenToTokenTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 51098}, {"name": "tokenToTokenSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 54928}, {"name": "tokenToTokenTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 55019}, {"name": "tokenToExchangeSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 49342}, {"name": "tokenToExchangeTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 49532}, {"name": "tokenToExchangeSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 53233}, {"name": "tokenToExchangeTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 53423}, {"name": "getEthToTokenInputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_sold"}], "constant": true, "payable": false, "type": "function", "gas": 5542}, {"name": "getEthToTokenOutputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}], "constant": true, "payable": false, "type": "function", "gas": 6872}, {"name": "getTokenToEthInputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}], "constant": true, "payable": false, "type": "function", "gas": 5637}, {"name": "getTokenToEthOutputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}], "constant": true, "payable": false, "type": "function", "gas": 6897}, {"name": "tokenAddress", "outputs": [{"type": "address", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1413}, {"name": "factoryAddress", "outputs": [{"type": "address", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1443}, {"name": "balanceOf", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "address", "name": "_owner"}], "constant": true, "payable": false, "type": "function", "gas": 1645}, {"name": "transfer", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_to"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 75034}, {"name": "transferFrom", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_from"}, {"type": "address", "name": "_to"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 110907}, {"name": "approve", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_spender"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 38769}, {"name": "allowance", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "address", "name": "_owner"}, {"type": "address", "name": "_spender"}], "constant": true, "payable": false, "type": "function", "gas": 1925}, {"name": "name", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1623}, {"name": "symbol", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1653}, {"name": "decimals", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1683}, {"name": "totalSupply", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1713}]) | |
function getTotalSupply(token, contract=basicTokenInfo) { | |
return new Promise((ok,er)=>{ | |
contract.at(token).totalSupply.call((e,r)=>{if(e) er(e); else ok(r);}) | |
}) | |
} | |
function getTotalSupplyBn(token) { | |
const N = web3.BigNumber; | |
return getTotalSupply(token).then(ts=>new N(ts)).then(bn=>{ | |
return getDecimals(token).then(decimals => (new N(10).pow(-decimals)).mul(bn)) | |
}) | |
} | |
function getDecimals(token, contract=basicTokenInfo) { | |
return !token || token==='0x0000000000000000000000000000000000000000' ? Promise.resolve(18) : | |
new Promise((ok,error)=>{ | |
contract.at(token).decimals.call((e,r)=>{if(e) error(e); else ok(r);}) | |
}) | |
} | |
function getName(token, contract=dsTokenContract) { | |
return !token || token==='0x0000000000000000000000000000000000000000' ? Promise.resolve('Ether') : | |
new Promise((ok,error) => { | |
try{contract.at(token).name.call((e,r)=>{if(e) error(e); else ok(r);})} catch(e) {error(e)} | |
}).then(name => { | |
return name && name!=='0x' && | |
name!=='0x0000000000000000000000000000000000000000000000000000000000000020' ? | |
name : getName(token, basicTokenInfo) | |
}).then(name => { | |
if (name.length!==66) return name | |
return parseBytesString(name.substring(0,name.indexOf('00')).substring(2)) | |
}) | |
} | |
function getSymbol(token, contract=dsTokenContract) { | |
return !token || token==='0x0000000000000000000000000000000000000000' ? Promise.resolve('ETH') : | |
new Promise((ok,error) => { | |
try{contract.at(token).symbol.call((e,r)=>{if(e) error(e); else ok(r);})} catch(e) {error(e)} | |
}).then(symbol => { | |
return symbol && symbol !=='0x' && | |
symbol!=='0x0000000000000000000000000000000000000000000000000000000000000020' ? | |
symbol : getSymbol(token, basicTokenInfo) | |
}).then(symbol => { | |
if (symbol.length!==66) return symbol | |
return parseBytesString(symbol.substring(0,symbol.indexOf('00')).substring(2)) | |
}) | |
} | |
function getTokenInfoByIndex(i, force=false, waitMs=100) { | |
return getExchangeTokenAddresses(force,waitMs) | |
.then(tokens=>getTokenInfo(tokens[i], force, waitMs)) | |
} | |
function getExchangeOfToken(token, force=false, waitMs=100) { | |
return getUniswapExchangeCreationLogInfo(force,waitMs) | |
.then(({tokens, exchanges})=>{ | |
const i = tokens.indexOf(token); | |
if (i<0) return | |
const exchange = exchanges[i]; | |
return { token, exchange } | |
}); | |
} | |
async function getTokenInfo(token, force=false, waitMs=100) { | |
const id = addrId(token); | |
const { tokens, exchanges } = await getUniswapExchangeCreationLogInfo(force,waitMs); | |
const exchange = exchanges[tokens.indexOf(token)]; | |
const decimals = await getDecimals(token); | |
const totalSupply = (await getTotalSupplyBn(token)).toFixed(8); | |
const exchangeSupply = await getExchangeTokenBalance(token); | |
const symbol = await getSymbol(token); | |
const name = await getName(token,exchangeContract).catch(()=>getName(token, basicTokenInfo)); | |
const info = { token, symbol, name, totalSupply, exchangeSupply, decimals, exchange, id }; | |
localStorage.setItem(id, JSON.stringify(info)) | |
return info | |
} | |
function getEtherscanApi(apiQueryArgs, force=false, waitMs=100) { | |
const storageKey = 'api.etherscan.io/api?'+apiQueryArgs; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData() { | |
return fetch(`https://${storageKey}&apikey=${apiKey}`).then(r=>r.json().then(select('result'))); | |
} | |
} | |
function getUniswapExchangeCreationLogInfo(force=false, waitMs=100) { | |
const storageKey = 'exchange creation logs'; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData(forced) { | |
return getEtherscanApi(`module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=${factoryAddress}&topic0=0x9d42cb017eb05bd8944ab536a8b35bc68085931dd5f4356489801453923953f9`, forced, waitMs) | |
.then(exchanges => ({ | |
raw: exchanges, | |
exchanges: exchanges.map(topicToAddr(2)), | |
tokens: exchanges.map(topicToAddr(1)), | |
})) | |
} | |
} | |
function getExchangeAddresses(force=false, waitMs=100) { | |
const storageKey = 'exchange addresses'; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData(forced) { | |
return getUniswapExchangeCreationLogInfo(forced).then(select('exchanges')) | |
} | |
} | |
function getExchangeTokenAddresses(force=false, waitMs=100) { | |
const storageKey = 'exchange token addresses'; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData(forced) { | |
return getUniswapExchangeCreationLogInfo(forced, waitMs).then(select('tokens')) | |
} | |
} | |
async function getExchangeTokenBalance(token, force=false, waitMs=100) { | |
const symbol = await getSymbol(token); | |
const exchange = await getExchangeOfToken(token,force,waitMs); | |
const storageKey = `exchange token balance ${symbol} of ${addrId(exchange)}` | |
return getDelayed({storageKey, fetchData}, force, waitMs) | |
function fetchData(forced) { | |
const queryArgs = `module=account&action=tokenbalance&contractaddress=${token}&address=${exchange}&tag=latest`; | |
return getEtherscanApi(queryArgs, force, waitMs).then(balance=>{ | |
// TODO: should this check if greater than the token's totalSupply()? | |
if (balance || balance==='0') return { token, exchange, balance } | |
else throw 'token balance fetch failed' | |
}) | |
} | |
} | |
function getTokenBalance(token, address, force=false, waitMs=100) { | |
const storageKey = `token balance ${addrId(token)} of ${addrId(address)}` | |
return getDelayed({storageKey, fetchData}, force, waitMs) | |
function fetchData(forced) { | |
const queryArgs = `module=account&action=tokenbalance&contractaddress=${token}&address=${address}&tag=latest`; | |
return getEtherscanApi(queryArgs, force, waitMs).then(balance=>{ | |
// TODO: this should check if greater than the token's totalSupply() | |
//if (new Number(balance) > 10**36) return { token, address, balance: 0} else | |
if (balance || balance==='0') return { token, address, balance } | |
else throw 'token balance fetch failed' | |
}) | |
} | |
} | |
function getExchangeTokenBalances(force=false, waitMs=100) { | |
const storageKey = 'exchange token balances'; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData(forced) { | |
return getUniswapExchangeCreationLogInfo(forced,waitMs) | |
.then(info=>info.exchanges.map((address,i)=>({ address, token:info.tokens[i] }))) | |
.then(ia=>chainPromises(ia.map(({address,token})=>getTokenBalance(token,address,forced,waitMs).catch(e=>{})))) | |
} | |
} | |
function getTotalExchangeEthBalances(force=false, waitMs=100) { | |
const storageKey = 'exchanges total ether balance'; | |
return getDelayed({ storageKey, fetchData }, force, waitMs) | |
function fetchData(forced) { | |
const N = web3.BigNumber; | |
const Z = new N(0), W = new N(10**-18); | |
let r = getExchangeAddresses(forced,waitMs).then(fetchBalances); | |
if (!forced) | |
r = r.then(savePromiseToLocalStorage('exchange eth balances')); | |
return r.then(balances=>balances.map(select('balance')).filter(x=>x.balance!=0)) | |
.then(balances=>W.mul(balances.reduce((p,v)=>p.add(new N(v)),Z))) | |
} | |
function fetchBalances(addrs=[]) { | |
let subset = addrs.slice(0, 20); | |
return subset.length < 20 ? | |
fetch20(subset) : | |
fetch20(subset).then(balances=>fetchBalances(addrs.slice(20)).then(more=>[ ...balances, ...more ])) | |
} | |
async function fetch20(a=[]) { | |
return await getEtherscanApi(`module=account&action=balancemulti&address=${a.join(',')}&tag=latest`) | |
} | |
} | |
function getAllTokenInfos(force=false, waitMs=100) { | |
return getExchangeTokenAddresses(force, waitMs) | |
.then(tokens=>chainPromises(tokens.map(t=>getTokenInfo(t, force, waitMs)))) | |
} | |
async function getTokenInfoByIndex(i, force=false, waitMs=100) { | |
await getExchangeAddresses(force,waitMs); | |
const tokens = await getExchangeTokenAddresses(force,waitMs); | |
return getTokenInfo(tokens[i], force, waitMs) | |
} | |
async function logTotalExchangeEthBalances(force=false, waitMs=100) { | |
const balances = {ETH: (await getTotalExchangeEthBalances(force,waitMs))}; | |
console.log(balances); | |
return balances | |
} | |
function getTokenInfoByExchange(address, force=false, waitMs=100) { | |
return getExchangeAddresses(force, waitMs) | |
.then(exchanges=>getTokenInfoByIndex(exchanges.indexOf(address), force, waitMs)) | |
} | |
function getExchangesWithOver(ether, force=false, waitMs=100) { | |
return logTotalExchangeEthBalances(force, waitMs) | |
.then(()=>JSON.parse(localStorage.getItem('exchange eth balances'))) | |
.then(bs=>bs.filter(x=>0!=x.balance)) | |
.then(bs=>bs.map(b=>({...b, balance:web3.toBigNumber(b.balance)}))) | |
.then(bs=>bs.filter(x=>x.balance.gt(ether*10**18))) | |
.then(bs=>bs.map(b=>({...b, balance: b.balance.toNumber()}))) | |
.then(bs=>bs.map(async b=>({...b, token: await getTokenInfoByExchange(b.account) }))) | |
} | |
function getBytecode(contract) { | |
return new Promise((ok,er)=>{ | |
web3.eth.getCode(contract,(e,r)=>{if(e)er(e); else ok(r);}) | |
}) | |
} | |
function onweb3(e,r) {if (e) throw e; console.log(r)} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment