Skip to content

Instantly share code, notes, and snippets.

@destenson
Last active November 21, 2018 19:42
Show Gist options
  • Save destenson/69da2ddde8b97dae9a6622c6cb7e9ad5 to your computer and use it in GitHub Desktop.
Save destenson/69da2ddde8b97dae9a6622c6cb7e9ad5 to your computer and use it in GitHub Desktop.
Some random etherscan/uniswap code
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