async def cmd_tokens_minted(command_str, discord_message, apis): if apis.token.tokens_minted == None: return ":shrug:" fmt_str = "Tokens in circulation: **{}** / {} {}" result = fmt_str.format(prettify_decimals(apis.token.tokens_minted), prettify_decimals(apis.token.total_supply), apis.token.symbol) return result
def run_function_and_time_it(function_name, iterations): import timeit timer = timeit.Timer( "{}()".format(function_name), "gc.enable(); from main import {}".format(function_name)) speed = min(timer.repeat(repeat=3, number=iterations)) time_per_run = speed / iterations messages_per_sec = 1 / (speed / iterations) fmt_str = "{:>23}:{:>12} seconds per call{:>12} runs per sec" logging.info( fmt_str.format(function_name, formatting_helpers.prettify_decimals(time_per_run), formatting_helpers.prettify_decimals(messages_per_sec)))
def parse_mining_results(apis, nonce, digest, save_high_score=False, author_name=None, author_id=None): resulting_difficulty = apis.token.max_target / Web3.toInt(digest) percent_of_the_way_to_full_target = apis.token.mining_target / Web3.toInt(digest) fmt_str = "Nonce `0x{}...` -> Digest `0x{}...`\nDiff: {} ({}% of the way to a full solution)" result = fmt_str.format(nonce[:5].hex(), digest[:5].hex(), prettify_decimals(resulting_difficulty), prettify_decimals(percent_of_the_way_to_full_target * 100.0)) if save_high_score: result += check_and_set_top_share(apis, resulting_difficulty, author_name, author_id, digest) return result
async def cmd_marketcap(command_str, discord_message, apis): if apis.exchanges.last_updated_time() == 0: return "not sure yet... waiting on my APIs :sob: [<{}>]".format(apis.exchanges.short_url()) token_price = apis.exchanges.price_eth(config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() marketcap = apis.token.tokens_minted * token_price if marketcap == 0: return ":shrug:" fmt_str = "Marketcap: **${}** (Price: ${} Circulating Supply: {})" result = fmt_str.format(prettify_decimals(marketcap), prettify_decimals(token_price), prettify_decimals(apis.token.tokens_minted)) return result
def run_command_fuzzer(): import logging import asyncio import time from main import apis, manual_api_update from formatting_helpers import prettify_decimals commands_per_log_message = 150000 # about 1 hour on a 4th gen i7 logging.info( "Starting fuzz test. Ctrl+C to exit. Errors are logged to console.") asyncio.get_event_loop().run_until_complete(manual_api_update()) time_last = time.time() # no seed; each run should be unique for idx, command_str in enumerate(get_fuzzing_iterator()): run_and_log_command(apis, command_str) if idx != 0 and idx % commands_per_log_message == 0: time_now = time.time() time_delta = time_now - time_last time_per_command = time_delta / commands_per_log_message commands_per_second = 1 / time_per_command time_last = time_now fmt_str = "{:>14} commands {:>14} cmds/sec" logging.info( fmt_str.format(idx, prettify_decimals(commands_per_second)))
async def cmd_all_time_high(command_str, discord_message, apis): time_eth = unix_timestamp_to_readable_date(apis.storage.all_time_high_eth_timestamp.get()) time_usd = unix_timestamp_to_readable_date(apis.storage.all_time_high_usd_timestamp.get()) if time_eth == time_usd: fmt_str = "All time high: **{}Ξ** **${}** ({})" result = fmt_str.format(prettify_decimals(apis.storage.all_time_high_eth_price.get()), prettify_decimals(apis.storage.all_time_high_usd_price.get()), time_usd) else: fmt_str = "All time high: \n**{}Ξ** ({}) **${}** ({})" result = fmt_str.format(prettify_decimals(apis.storage.all_time_high_eth_price.get()), time_eth, prettify_decimals(apis.storage.all_time_high_usd_price.get()), time_usd) return result
async def cmd_income(command_str, discord_message, apis): if apis.token.difficulty is None: return "not sure yet... waiting on my APIs :sob:" try: command, hashrate = command_str.split(maxsplit=1) except: return "Bad hashrate; try `!income 5`, `!income 300mh`, or `!income 2.8gh`" multipliers = ( ('k', 1e3), ('m', 1e6), ('g', 1e9), ('t', 1e12), ('p', 1e15), ('e', 1e18), ('z', 1e21), ('y', 1e24)) selected_multiplier = 1e9 for char, mult in multipliers: if char in hashrate: selected_multiplier = mult match = re.match("([<\d.,]+)", hashrate) if not match: return "Bad hashrate; try `!income 5`, `!income 300mh`, or `!income 2.8gh`" try: hashrate = string_to_float(match.group(1)) * selected_multiplier except ValueError: return "Bad hashrate; try `!income 5`, `!income 300mh`, or `!income 2.8gh`" if hashrate == 0: return "Bad hashrate; try `!income 5`, `!income 300mh`, or `!income 2.8gh`" tokens_per_day = 0.8 * 86400 * apis.token.reward * hashrate / ((2**22) * apis.token.difficulty) seconds_per_block = 1.2 * ((2**22) * apis.token.difficulty) / hashrate if tokens_per_day > 1: tokens_over_time_str = "**{}** tokens/day".format(prettify_decimals(tokens_per_day)) else: tokens_over_time_str = "**{}** tokens/week".format(prettify_decimals(tokens_per_day*7)) fmt_str = "Income for {}: {}; **{}** per block solo" return fmt_str.format(to_readable_thousands(hashrate, unit_type='hashrate'), tokens_over_time_str, seconds_to_time(seconds_per_block))
def test_fuzzing_prettify_decimals(self): from formatting_helpers import prettify_decimals import random iterations = 100000 # 4 seconds on an i7-5700HQ min_value, max_value = -1e30, 1e30 # fixed seed so randomness is repeatable myrandom = random.Random("myseed") # test formatting integers for _ in range(iterations): number = myrandom.randint(min_value, max_value) with self.subTest(number=number): formatted = prettify_decimals(number) self.assertTrue(isinstance(formatted, str)) self.assertTrue(len(formatted) <= 16) # test formatting floats for _ in range(iterations): number = myrandom.uniform(min_value, max_value) with self.subTest(number=number): formatted = prettify_decimals(number) self.assertTrue(isinstance(formatted, str)) self.assertTrue(len(formatted) <= 16)
async def check_update_all_time_high(apis): price_eth = apis.exchanges.price_eth(config.TOKEN_SYMBOL) price_usd = apis.exchanges.price_eth( config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() if (price_eth > 100 * apis.storage.all_time_high_eth_price.get() or price_usd > 100 * apis.storage.all_time_high_usd_price.get()): # check for prices so high they are likely bugs logging.warning( f"Prevented ATH announcement due to price too high ({price_eth} eth {price_usd} usd)" ) return try: if (price_usd > apis.storage.all_time_high_usd_price.get() and formatting_helpers.prettify_decimals(price_usd) != formatting_helpers.prettify_decimals( apis.storage.all_time_high_usd_price.get())): msg = 'New USD all-time-high **${}**'.format( formatting_helpers.prettify_decimals(price_usd)) await send_all_time_high_announcement(apis, msg) apis.storage.all_time_high_usd_price.set(price_usd) apis.storage.all_time_high_usd_timestamp.set(time.time()) if (price_eth > apis.storage.all_time_high_eth_price.get() and formatting_helpers.prettify_decimals(price_eth) != formatting_helpers.prettify_decimals( apis.storage.all_time_high_eth_price.get())): msg = 'New Ethereum all-time-high **{}Ξ**'.format( formatting_helpers.prettify_decimals(price_eth)) await send_all_time_high_announcement(apis, msg) apis.storage.all_time_high_eth_price.set(price_eth) apis.storage.all_time_high_eth_timestamp.set(time.time()) except Exception as e: logging.exception(f"Failed to compare and/or save ATH data: {str(e)}")
async def check_update_all_time_high(apis): try: price_eth = apis.exchanges.price_eth(config.TOKEN_SYMBOL) price_usd = apis.exchanges.price_eth( config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() if (price_usd > apis.storage.all_time_high_usd_price.get() and formatting_helpers.prettify_decimals(price_usd) != formatting_helpers.prettify_decimals( apis.storage.all_time_high_usd_price.get())): msg = 'New USD all-time-high **${}**'.format( formatting_helpers.prettify_decimals(price_usd)) await send_all_time_high_announcement(apis, msg) apis.storage.all_time_high_usd_price.set(price_usd) apis.storage.all_time_high_usd_timestamp.set(time.time()) if (price_eth > apis.storage.all_time_high_eth_price.get() and formatting_helpers.prettify_decimals(price_eth) != formatting_helpers.prettify_decimals( apis.storage.all_time_high_eth_price.get())): msg = 'New Ethereum all-time-high **{}Ξ**'.format( formatting_helpers.prettify_decimals(price_eth)) await send_all_time_high_announcement(apis, msg) apis.storage.all_time_high_eth_price.set(price_eth) apis.storage.all_time_high_eth_timestamp.set(time.time()) except: logging.exception('Failed to save ATH data')
async def cmd_compare_price_vs(apis, item_name="lambo", item_price=200000): if apis.exchanges.last_updated_time() == 0: return ":shrug:" token_price_usd = apis.exchanges.price_eth(config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() if token_price_usd == 0: return ":shrug:" return "1 {} = **{}** {} (${})".format(item_name, prettify_decimals(item_price / token_price_usd), config.TOKEN_SYMBOL, to_readable_thousands(item_price))
async def cmd_balance_of(command_str, discord_message, apis): if apis.token.estimated_hashrate_since_readjustment == None: return ":shrug:" try: address = command_str.split()[-1:][0] address = Web3.toChecksumAddress(address) except: return "Bad address, try `!balance of 0x0000000000000000000000000000000000000000`" try: fmt_str = "0xBitcoin balance: **{}** 0xBTC." result = fmt_str.format(prettify_decimals(apis.token.balance_of(address))) except: logging.exception('exception in token.balance_of') return ":shrug:" else: return result
def check_and_set_top_share(apis, resulting_difficulty, author_name, author_id, digest): result = "" if resulting_difficulty > apis.storage.top_miner_difficulty.get(): fmt_str = "\nNew best share! Previous was `0x{}...` (Difficulty: {}) by {}" result += fmt_str.format(apis.storage.top_miner_digest.get()[:5].hex(), prettify_decimals(apis.storage.top_miner_difficulty.get()), apis.storage.top_miner_name.get()) apis.storage.top_miner_difficulty.set(resulting_difficulty) apis.storage.top_miner_name.set(author_name) apis.storage.top_miner_id.set(author_id) apis.storage.top_miner_digest.set(digest) # in case someone solves a block... never going to happen but why not? if Web3.toInt(digest) <= apis.token.mining_target: result += "\n~~~~~" result += "\n:money_mouth: You seem to have solved a block!? Try your luck here [<https://etherscan.io/address/0xb6ed7644c69416d67b522e20bc294a9a9b405b31#writeContract>]" result += "\nMake sure you log into metamask using the public address you have set here, and type these values into the mint() function:" result += "\n nonce=`{}`".format(Web3.toHex(nonce)) result += "\n challenge_digest=`{}`".format(Web3.toHex(digest)) result += "\n~~~~~" return result
async def cmd_volume(command_str, discord_message, apis): if apis.exchanges.last_updated_time() == 0: return "not sure yet... waiting on my APIs :sob: [<{}>]".format(apis.exchanges.short_url()) total_eth_volume = 0 total_btc_volume = 0 response = "" for api in sorted(apis.exchanges.alive_exchanges, key=lambda a: a.exchange_name): # skip CMC and apis not directly tracking main currency if api.currency_symbol != config.TOKEN_SYMBOL or api.exchange_name == "Coin Market Cap": continue volume_eth = apis.exchanges.volume_eth(config.TOKEN_SYMBOL, exchange_name=api.exchange_name) volume_btc = apis.exchanges.volume_btc(config.TOKEN_SYMBOL, exchange_name=api.exchange_name) if volume_eth == 0 and volume_btc == 0: continue total_eth_volume += volume_eth total_btc_volume += volume_btc if apis.exchanges.eth_price_usd() == 0: response += "{}: **{}Ξ** ".format(api.exchange_name, prettify_decimals(volume_eth)) else: response += "{}: $**{}**({}Ξ) ".format(api.exchange_name, prettify_decimals(volume_eth * apis.exchanges.eth_price_usd()), prettify_decimals(volume_eth)) if volume_btc != 0: if apis.exchanges.btc_price_usd() == 0: response += "+ **{}₿** ".format(prettify_decimals(volume_btc)) else: response += "+ $**{}**({}₿) ".format(prettify_decimals(volume_btc * apis.exchanges.btc_price_usd()), prettify_decimals(volume_btc)) response += "\n" if apis.exchanges.eth_price_usd() == 0 or apis.exchanges.btc_price_usd() == 0: response += "Total: {}Ξ + {}₿".format(prettify_decimals(total_eth_volume), prettify_decimals(total_btc_volume)) else: response += "Total: $**{}**({}Ξ+{}₿)".format(prettify_decimals((total_eth_volume * apis.exchanges.eth_price_usd()) + (total_btc_volume * apis.exchanges.btc_price_usd())), prettify_decimals(total_eth_volume), prettify_decimals(total_btc_volume)) if "better" in command_str: # !bettervolume return ':star2:'*10 + '\n' + response + '\n' + ':star2:'*10 else: return response
def convert(amount, src, dest, apis): src = src.lower() dest = dest.lower() amount = string_to_float(amount) usd_value, result = None, None token_price_usd = apis.exchanges.price_eth(config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() if config.TOKEN_SYMBOL != "0xBTC": logging.warning("unknown currency {}; !convert command assumes 0xBTC".format(config.TOKEN_SYMBOL)) if src in ['0xbtc', '0xbitcoins', '0xbitcoin']: usd_value = token_price_usd * amount elif src in ['m0xbtc', 'milli0xbtc', 'milli0xbitcoin', 'milli0xbitcoins']: usd_value = token_price_usd * amount / 1000.0 elif src in ['0xsatoshis', '0xsatoshi', 'satoastis', 'satoasti', 'crumbs', 'crumb']: usd_value = token_price_usd * amount / 10**8 elif src in ['eth', 'ethereum', 'ether']: usd_value = apis.exchanges.eth_price_usd() * amount elif src == 'wei': usd_value = apis.exchanges.eth_price_usd() * amount / 10**18 elif src in ['btc', 'bitcoins', 'bitcoin']: usd_value = apis.exchanges.btc_price_usd() * amount elif src in ['mbtc', 'millibtc', 'millibitcoins', 'millibitcoin']: usd_value = apis.exchanges.btc_price_usd() * amount / 1000.0 elif src in ['satoshis', 'satoshi']: usd_value = apis.exchanges.btc_price_usd() * amount / 10**8 elif src in ['usd', 'dollars', 'dollar', 'ddollar', 'bucks', 'buck']: usd_value = amount elif src in ['cents', 'cent']: usd_value = amount / 100.0 else: for price, names in config.EXPENSIVE_STUFF: if util.string_contains_any(src, names, exhaustive_search=True, require_cmd_char=False): src = names[0] # replace name with the non-typo'd version usd_value = amount * price break if usd_value == None: return "Bad currency ({}). 0xbtc, 0xsatoshis, eth, wei, btc, mbtc, satoshis, and usd are supported.".format(src) if dest in ['0xbtc', '0xbitcoins', '0xbitcoin']: result = usd_value / token_price_usd elif dest in ['m0xbtc', 'milli0xbtc', 'milli0xbitcoin', 'milli0xbitcoins']: result = 1000.0 * usd_value / token_price_usd elif dest in ['0xsatoshis', '0xsatoshi', 'satoastis', 'satoasti', 'crumbs', 'crumb']: result = 10**8 * usd_value / token_price_usd elif dest in ['eth', 'ethereum', 'ether']: result = usd_value / apis.exchanges.eth_price_usd() elif dest == 'wei': result = 10**18 * usd_value / apis.exchanges.eth_price_usd() elif dest in ['btc', 'bitcoins', 'bitcoin']: result = usd_value / apis.exchanges.btc_price_usd() elif dest in ['mbtc', 'millibtc', 'millibitcoins', 'millibitcoin']: result = usd_value * 1000.0 / apis.exchanges.btc_price_usd() elif dest in ['satoshis', 'satoshi']: result = 10**8 * usd_value / apis.exchanges.btc_price_usd() elif dest in ['usd', 'dollars', 'dollar', 'ddollar', 'bucks', 'buck']: result = usd_value elif dest in ['cents', 'cent']: result = usd_value * 100.0 else: for price, names in config.EXPENSIVE_STUFF: if util.string_contains_any(dest, names, exhaustive_search=True, require_cmd_char=False): dest = names[0] # replaces provided name with the non-typo'd version result = usd_value / price break if result == None: return "Bad currency ({}). 0xbtc, 0xsatoshis, eth, wei, btc, mbtc, satoshis, and usd are supported.".format(dest) amount = prettify_decimals(amount) result = prettify_decimals(result) return "{} {} = **{}** {}".format(amount, src, result, dest)
async def background_update(): try: await apis.gas_price_api.update() except RuntimeError as e: logging.warning('Failed to update gas price: {}'.format(str(e))) except: logging.exception('Failed to update gas price') # TODO: time this. even better: time each exchange try: await apis.exchanges.update() except RuntimeError as e: logging.warning('Failed to update exchange APIs: {}'.format(str(e))) except: logging.exception('Failed to update exchange APIs') try: apis.token.update() except RuntimeError as e: logging.warning('Failed to update contract info: {}'.format(str(e))) except: logging.exception('Failed to update contract info') # removed holders chart updates until etherscan.py works again # # if (time.time() - apis.storage.last_holders_update_timestamp.get()) / 3600.0 > config.TOKEN_HOLDER_UPDATE_RATE_HOURS: # try: # etherscan.update_saved_holders_chart(config.TOKEN_NAME, # config.TOKEN_ETH_ADDRESS, # apis.token.tokens_minted) # apis.storage.last_holders_update_timestamp.set(time.time()) # except TimeoutError: # logging.warning('Failed to update token holders chart') # except: # logging.exception('Failed to update token holders chart') # else: # logging.info('Updated token holders chart') try: await check_update_all_time_high(apis) except: logging.exception('Failed to check all time high') try: price_eth = apis.exchanges.price_eth(config.TOKEN_SYMBOL) price_usd = apis.exchanges.price_eth( config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() # usd price is hidden if it is 0 (an error) usd_str = "" if price_usd == 0 else "${:.2f} | ".format(price_usd) # show hashrate if available, otherwise show 'time since last update' if apis.token.estimated_hashrate_since_readjustment is not None and apis.token.estimated_hashrate_since_readjustment > 0: end_of_status = formatting_helpers.to_readable_thousands( apis.token.estimated_hashrate_since_readjustment, unit_type='short_hashrate') else: end_of_status = formatting_helpers.seconds_to_n_time_ago( time.time() - apis.exchanges.last_updated_time()) # wait until at least one successful update to show status if apis.exchanges.last_updated_time() != 0: fmt_str = "{}{} Ξ ({})" await update_status( client, fmt_str.format(usd_str, formatting_helpers.prettify_decimals(price_eth), end_of_status)) except (websockets.exceptions.ConnectionClosed, RuntimeError) as e: logging.warning('Falied to change status: {}'.format(str(e))) except: logging.exception('Failed to change status')
async def cmd_bestshare(command_str, discord_message, apis): fmt_str = "Best share digest: `0x{}...` (Difficulty: {}) by {}" result = fmt_str.format(apis.storage.top_miner_digest.get()[:16].hex(), prettify_decimals(apis.storage.top_miner_difficulty.get()), apis.storage.top_miner_name.get()) return result
def test_prettify_decimals(self): from formatting_helpers import prettify_decimals self.assertEqual(prettify_decimals(0), '0') self.assertEqual(prettify_decimals(0.0032), '0.0032') self.assertEqual(prettify_decimals(0.00160), '0.0016') self.assertEqual(prettify_decimals(0.00000000000000123456), '1.23e-15') self.assertEqual(prettify_decimals(0.0000000000000123456), '1.23e-14') self.assertEqual(prettify_decimals(0.000000000000123456), '1.23e-13') self.assertEqual(prettify_decimals(0.00000000000123456), '0.00000000000123') self.assertEqual(prettify_decimals(0.0000000000123456), '0.0000000000123') self.assertEqual(prettify_decimals(0.000000000123456), '0.000000000123') self.assertEqual(prettify_decimals(0.00000000123456), '0.00000000123') self.assertEqual(prettify_decimals(0.0000000123456), '0.0000000123') self.assertEqual(prettify_decimals(0.000000123456), '0.000000123') self.assertEqual(prettify_decimals(0.00000123456), '0.00000123') self.assertEqual(prettify_decimals(0.0000123456), '0.0000123') self.assertEqual(prettify_decimals(0.000123456), '0.000123') self.assertEqual(prettify_decimals(0.00123456), '0.00123') self.assertEqual(prettify_decimals(0.012345678), '0.0123') self.assertEqual(prettify_decimals(0.12345678), '0.123') self.assertEqual(prettify_decimals(1.2345678), '1.235') self.assertEqual(prettify_decimals(12.345678), '12.35') self.assertEqual(prettify_decimals(123.45678), '123.46') self.assertEqual(prettify_decimals(1234.5678), '1234.57') self.assertEqual(prettify_decimals(12345.6789), '12,346') self.assertEqual(prettify_decimals(12345), '12,345') self.assertEqual(prettify_decimals(123456789), '123,456,789') self.assertEqual(prettify_decimals(1234567890), '1.2 billion') self.assertEqual(prettify_decimals(12345678901), '12.3 billion') self.assertEqual(prettify_decimals(123456789012), '123.5 billion') self.assertEqual(prettify_decimals(12345678901234), '12.3 trillion') self.assertEqual(prettify_decimals(123456789012345), '123.5 trillion') self.assertEqual(prettify_decimals(1234567890123456), '1.23e15') self.assertEqual(prettify_decimals(12345678901234567), '1.23e16') self.assertEqual(prettify_decimals(123456789012345678), '1.23e17')
async def background_update(): await client.wait_until_ready() while not client.is_closed: try: await apis.exchanges.update() except RuntimeError as e: logging.warning('Failed to update exchange APIs: {}'.format( str(e))) except: logging.exception('Failed to update exchange APIs') try: apis.token.update() except RuntimeError as e: logging.warning('Failed to update contract info: {}'.format( str(e))) except: logging.exception('Failed to update contract info') if (time.time() - apis.storage.last_holders_update_timestamp.get() ) / 3600.0 > config.TOKEN_HOLDER_UPDATE_RATE_HOURS: try: etherscan.update_saved_holders_chart(config.TOKEN_NAME, config.TOKEN_ETH_ADDRESS, apis.token.tokens_minted) apis.storage.last_holders_update_timestamp.set(time.time()) except TimeoutError: logging.warning('Failed to update token holders chart') except: logging.exception('Failed to update token holders chart') else: logging.info('Updated token holders chart') await check_update_all_time_high(apis) try: price_eth = apis.exchanges.price_eth(config.TOKEN_SYMBOL) price_usd = apis.exchanges.price_eth( config.TOKEN_SYMBOL) * apis.exchanges.eth_price_usd() # usd price is hidden if it is 0 (an error) usd_str = "" if price_usd == 0 else "${:.2f} | ".format( price_usd) # show hashrate if available, otherwise show 'time since last update' if apis.token.estimated_hashrate_since_readjustment is not None and apis.token.estimated_hashrate_since_readjustment > 0: end_of_status = formatting_helpers.to_readable_thousands( apis.token.estimated_hashrate_since_readjustment, unit_type='short_hashrate') else: end_of_status = formatting_helpers.seconds_to_n_time_ago( time.time() - apis.exchanges.last_updated_time()) # wait until at least one successful update to show status if apis.exchanges.last_updated_time() != 0: fmt_str = "{}{} Ξ ({})" await update_status( client, fmt_str.format( usd_str, formatting_helpers.prettify_decimals(price_eth), end_of_status)) except (websockets.exceptions.ConnectionClosed, RuntimeError) as e: logging.warning('Falied to change status: {}'.format(str(e))) except: logging.exception('Failed to change status') await asyncio.sleep(config.UPDATE_RATE) # this throws an exception which causes the program to restart # in normal operation we should never reach this raise RuntimeError('background_update loop stopped - something is wrong')