def create_tor(): from ansi_management import (warning, success, error, info, clear_screen, bold, muted, yellow, blue) from config import Config # ---------------------------------------------- # Test Tor # ---------------------------------------------- with yaspin(text="Testing Tor", color="cyan") as spinner: from connections import test_tor tor = test_tor() if tor['status']: logging.info(success("Tor Connected")) spinner.ok("✅ ") spinner.text = success(" Tor Connected [Success]") print("") return (tor) else: logging.error(error("Could not connect to Tor")) spinner.fail("💥 ") spinner.text = warning(" Tor NOT connected [ERROR]") print(error(" Could not connect to Tor.")) print( info( " [i] If you have a Tor Browser installed try opening (leave it running) and try again." )) print( info(" [i] If you are running Linux try the command: ") + yellow('service tor start')) print( info( " or download Tor at: https://www.torproject.org/download/" )) print("")
def create_tor(): # ---------------------------------------------- # Test Tor # ---------------------------------------------- with yaspin(text="Testing Tor", color="cyan") as spinner: tor = test_tor() if tor['status']: logging.info(success("Tor Connected")) spinner.ok("✅ ") spinner.write(success(" Tor Connected [Success]")) print("") return (tor) else: logging.error(error("Could not connect to Tor")) spinner.fail("💥 ") spinner.write(warning(" Tor NOT connected [ERROR]")) print( error( " Could not connect to Tor. WARden requires Tor to run. Quitting..." )) print( info( " Download Tor at: https://www.torproject.org/download/" )) print("") exit()
def data_large_price(): from node_warden import load_config config = load_config(quiet=True) ft_config = config['MAIN'] font = ft_config.get('large_text_font') btc = btc_price_data() try: btc_price = cleanfloat(btc['DISPLAY']['BTC']['USD']['PRICE']) except Exception: return (error(' >> Error getting price data. Retrying...')) custom_fig = pyfiglet.Figlet(font=font) return_fig = custom_fig.renderText('$ ' + jformat(btc_price, 0)) return_fig = yellow(return_fig) chg_str = btc['DISPLAY']['BTC']['USD']['CHANGEPCTDAY'] chg = cleanfloat(chg_str) msg = '\n' if chg >= 0: msg += success(f'24hr Change: +{chg_str}%\n') if chg > 5: msg += (info("[NgU] ") + muted(f"Looks like Bitcoin is pumping ") + emoji.emojize(":rocket:")) if chg < 0: msg += error(f'24hr Change: {chg_str}%\n') if chg < -5: msg += muted( f"Bitcoin dropping? Buy the dip!\nTime to stack some sats. ") return_fig = muted(return_fig) return_fig += msg return (return_fig)
def data_random_satoshi(): from node_warden import load_config config = load_config(quiet=True) url = config['QUOTES'].get('url') try: quotes = tor_request(url).json() except Exception: return (error(' >> Error contacting server. Retrying... ')) quote = quotes[randrange(len(quotes))] return_str = info(f"Satoshi Quotes | Subject: {quote['category']}\n") return_str += muted(f"{quote['date']} on {quote['medium']}\n") return_str += yellow(f"{quote['text']} \n\n") return_str += muted("Source: Nakamoto Institute") return (return_str)
def data_logger(): from node_warden import debug_file lines = 8 log_txt = tail(debug_file, lines) return_str = [] for element in log_txt: if 'INFO' in element: return_str.append(info(element)) elif 'ERROR' in log_txt: return_str.append(error(element)) elif 'WARN' in log_txt: return_str.append(warning(element)) else: return_str.append((element)) return_str = ''.join(return_str) return return_str
def data_logger(): from node_warden import debug_file try: lines = 8 log_txt = tail(debug_file, lines) return_str = [] for element in log_txt: if 'INFO' in element: return_str.append(info(element)) elif 'ERROR' in log_txt: return_str.append(error(element)) elif 'WARN' in log_txt: return_str.append(warning(element)) else: return_str.append((element)) return_str = ''.join(return_str) except Exception: return yellow('>> Error Loading Log Messages. Retying...') return return_str
def check_for_pump(_loop, _data): try: btc = btc_price_data() btc_price = btc['DISPLAY']['BTC']['USD']['PRICE'] chg_str = btc['DISPLAY']['BTC']['USD']['CHANGEPCTDAY'] chg = cleanfloat(chg_str) if chg > 5: logging.info( info("[NgU] ") + muted(f"Looks like Bitcoin is pumping ") + emoji.emojize(":rocket:") + yellow(f' {btc_price}') + success(f' +{chg_str}%')) if chg < -5: logging.info( info("[NgU] ") + muted( f"Looks like Bitcoin is dropping. Time to stack some sats. " ) + yellow(f' {btc_price}') + error(f' {chg_str}%')) except Exception: pass main_loop.set_alarm_in(300, check_for_pump)
def load_config(quiet=False): # Load Config config_file = os.path.join(basedir, 'config.ini') CONFIG = configparser.ConfigParser() if quiet: CONFIG.read(config_file) return (CONFIG) with yaspin(text="Loading config.ini", color="cyan") as spinner: # Check that config file exists if os.path.isfile(config_file): CONFIG.read(config_file) spinner.ok("✅ ") spinner.write(success(" Config Loaded [Success]")) print("") return (CONFIG) else: spinner.fail("💥 ") spinner.write( warning(" Config file could not be loaded [ERROR]")) print(error(" WARden requires config.ini to run. Quitting...")) exit()
def init_app(app): from ansi_management import (warning, success, error) from utils import (create_config, runningInDocker) from config import Config from connections import tor_request warnings.filterwarnings('ignore') # Load config.ini into app # -------------------------------------------- # Read Global Variables from warden.config(s) # Can be accessed like a dictionary like: # app.settings['PORTFOLIO']['RENEW_NAV'] # -------------------------------------------- config_file = Config.config_file app.warden_status = {} # Check for internet connection internet_ok = internet_connected() if internet_ok is True: print(success("✅ Internet Connection")) else: print( error( "[!] WARden needs internet connection. Check your connection.") ) print(warning("[!] Exiting")) exit() # Config config_settings = configparser.ConfigParser() if os.path.isfile(config_file): config_settings.read(config_file) app.warden_status['initial_setup'] = False print( success( "✅ Config Loaded from config.ini - edit it for customization" )) else: print( error( " Config File could not be loaded, created a new one with default values..." )) create_config(config_file) config_settings.read(config_file) app.warden_status['initial_setup'] = True table_error = False try: # create empty instance of LoginManager app.login_manager = LoginManager() except sqlite3.OperationalError: table_error = True # Create empty instance of SQLAlchemy app.db = SQLAlchemy() app.db.init_app(app) # Import models so tables are created from models import Trades, User, AccountInfo, TickerInfo, SpecterInfo app.db.create_all() # There was an initial error on getting users # probably because tables were not created yet. # The above create_all should have solved it so try again. if table_error: # create empty instance of LoginManager app.login_manager = LoginManager() # If login required - go to login: app.login_manager.login_view = "warden.login" # To display messages - info class (Bootstrap) app.login_manager.login_message_category = "secondary" app.login_manager.init_app(app) # Create empty instance of messagehandler from message_handler import MessageHandler app.message_handler = MessageHandler() app.message_handler.clean_all() # Get Version print("") try: version_file = Config.version_file with open(version_file, 'r') as file: current_version = file.read().replace('\n', '') except Exception: current_version = 'unknown' with app.app_context(): app.version = current_version # Check if there are any users on database, if not, needs initial setup users = User.query.all() if users == []: app.warden_status['initial_setup'] = True # Check for Cryptocompare API Keys print("") check_cryptocompare() print("") print(f"[i] Running WARden version: {current_version}") app.warden_status['running_version'] = current_version # CHECK FOR UPGRADE repo_url = 'https://api.github.com/repos/pxsocs/warden/releases' try: github_version = tor_request(repo_url).json()[0]['tag_name'] except Exception: github_version = None app.warden_status['github_version'] = github_version if github_version: print(f"[i] Newest WARden version available: {github_version}") parsed_github = version.parse(github_version) parsed_version = version.parse(current_version) app.warden_status['needs_upgrade'] = False if parsed_github > parsed_version: print(warning(" [i] Upgrade Available")) app.warden_status['needs_upgrade'] = True if parsed_github == parsed_version: print(success("✅ You are running the latest version")) else: print(warning("[!] Could not check GitHub for updates")) print("") # Check if config.ini exists with app.app_context(): app.settings = config_settings with app.app_context(): try: from utils import fxsymbol app.fx = fxsymbol(config_settings['PORTFOLIO']['base_fx'], 'all') except KeyError: # Problem with this config, reset print(error(" [!] Config File needs to be rebuilt")) print("") create_config(config_file) # TOR Server through Onion Address -- # USE WITH CAUTION - ONION ADDRESSES CAN BE EXPOSED! # WARden needs to implement authentication (coming soon) if app.settings['SERVER'].getboolean('onion_server'): from stem.control import Controller from urllib.parse import urlparse app.tor_port = app.settings['SERVER'].getint('onion_port') app.port = app.settings['SERVER'].getint('port') from warden_modules import home_path toraddr_file = os.path.join(home_path(), "onion.txt") app.save_tor_address_to = toraddr_file proxy_url = "socks5h://localhost:9050" tor_control_port = "" try: tor_control_address = urlparse(proxy_url).netloc.split(":")[0] if tor_control_address == "localhost": tor_control_address = "127.0.0.1" app.controller = Controller.from_port( address=tor_control_address, port=int(tor_control_port) if tor_control_port else "default", ) except Exception: app.controller = None from tor import start_hidden_service start_hidden_service(app) from routes import warden from errors.handlers import errors from api.routes import api from csv_routes.routes import csv_routes from user_routes.routes import user_routes from simulator.routes import simulator app.register_blueprint(warden) app.register_blueprint(errors) app.register_blueprint(api) app.register_blueprint(csv_routes) app.register_blueprint(user_routes) app.register_blueprint(simulator) # Prepare app to receive Specter Server info # For the first load, just get a saved file if available # The background jobs will update later with app.app_context(): from specter_importer import Specter app.specter = Specter() app.specter.refresh_txs(load=True) app.downloading = False with app.app_context(): app.runningInDocker = runningInDocker() with app.app_context(): app.tor = create_tor() # Check if home folder exists, if not create home = str(Path.home()) home_path = os.path.join(home, 'warden/') try: os.makedirs(os.path.dirname(home_path)) except Exception: pass # Start Schedulers from backgroundjobs import (background_settings_update, background_specter_update, background_scan_network, background_specter_health, background_mempool_seeker) def bk_su(): with app.app_context(): background_specter_update() def bk_stu(): with app.app_context(): background_settings_update() def bk_scan(): with app.app_context(): background_scan_network() def bk_specter_health(): with app.app_context(): background_specter_health() def bk_mempool_health(): with app.app_context(): background_mempool_seeker() app.scheduler = BackgroundScheduler() app.scheduler.add_job(bk_su, 'interval', seconds=1) app.scheduler.add_job(bk_stu, 'interval', seconds=1) app.scheduler.add_job(bk_scan, 'interval', seconds=1) app.scheduler.add_job(bk_specter_health, 'interval', seconds=1) app.scheduler.add_job(bk_mempool_health, 'interval', seconds=1) app.scheduler.start() print(success("✅ Background jobs running")) print("") app.app_context().push() print(success("✅ Application startup is complete")) return app
def check_cryptocompare(): from utils import pickle_it with yaspin(text="Testing price grab from Cryptocompare", color="green") as spinner: data = {'Response': 'Error', 'Message': None} try: api_key = pickle_it('load', 'cryptocompare_api.pkl') if api_key != 'file not found': baseURL = ( "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC" + "&tsyms=USD&api_key=" + api_key) req = requests.get(baseURL) data = req.json() btc_price = (data['DISPLAY']['BTC']['USD']['PRICE']) spinner.text = (success(f"BTC price is: {btc_price}")) spinner.ok("✅ ") pickle_it('save', 'cryptocompare_api.pkl', api_key) return else: data = {'Response': 'Error', 'Message': 'No API Key is set'} except Exception as e: data = {'Response': 'Error', 'Message': str(e)} logging.error(data) try: if data['Response'] == 'Error': spinner.color = 'yellow' spinner.text = "CryptoCompare Returned an error " + data[ 'Message'] # ++++++++++++++++++++++++++ # Load Legacy # ++++++++++++++++++++++++++ try: # Let's try to use one of the # legacy api keys stored under cryptocompare_api.keys file # You can add as many as you'd like there filename = 'warden/static/cryptocompare_api.keys' file = open(filename, 'r') for line in file: legacy_key = str(line) spinner.text = ( warning(f"Trying different API Keys...")) baseURL = ( "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC" + "&tsyms=USD&api_key=" + legacy_key) try: data = None logging.debug(f"Trying API Key {legacy_key}") request = requests.get(baseURL) data = request.json() btc_price = ( data['DISPLAY']['BTC']['USD']['PRICE']) spinner.text = ( success(f"BTC price is: {btc_price}")) spinner.ok("✅ ") logging.debug(f"API Key {legacy_key} Success") pickle_it('save', 'cryptocompare_api.pkl', legacy_key) return except Exception as e: logging.debug(f"API Key {legacy_key} ERROR: {e}") logging.debug( f"API Key {legacy_key} Returned: {data}") spinner.text = "Didn't work... Trying another." except Exception: pass spinner.text = (error("Failed to get API Key - read below.")) spinner.fail("[!]") print( ' -----------------------------------------------------------------' ) print(yellow(" Looks like you need to get an API Key. ")) print(yellow(" The WARden comes with a shared key that")) print(yellow(" eventually gets to the call limit.")) print( ' -----------------------------------------------------------------' ) print( yellow( ' Go to: https://www.cryptocompare.com/cryptopian/api-keys' )) print( yellow( ' To get an API Key. Keys from cryptocompare are free.' )) print( yellow( ' [Tip] Get a disposable email to signup and protect privacy.' )) print( yellow( ' Services like https://temp-mail.org/en/ work well.' )) print(muted(" Current API:")) print(f" {api_key}") new_key = input(' Enter new API key (Q to quit): ') if new_key == 'Q' or new_key == 'q': exit() pickle_it('save', 'cryptocompare_api.pkl', new_key) check_cryptocompare() except KeyError: try: btc_price = (data['DISPLAY']['BTC']['USD']['PRICE']) spinner.ok("✅ ") spinner.write(success(f"BTC price is: {btc_price}")) pickle_it('save', 'cryptocompare_api.pkl', api_key) return except Exception: spinner.text = ( warning("CryptoCompare Returned an UNKNOWN error")) spinner.fail("💥 ") return (data)
def data_btc_price(): from node_warden import launch_logger launch_logger() from node_warden import load_config config = load_config(quiet=True) fx_config = config['CURRENCIES'] currencies = ast.literal_eval(fx_config.get('fx_list')) primary_fx = ast.literal_eval(fx_config.get('primary_fx')) price_data = multiple_price_grab('BTC', ','.join(currencies)) # Get prices in different currencies tabs = [] btc_usd_price = 0 for fx in currencies: try: price_str = price_data['DISPLAY']['BTC'][fx]['PRICE'] chg_str = price_data['DISPLAY']['BTC'][fx]['CHANGEPCTDAY'] high = price_data['DISPLAY']['BTC'][fx]['HIGHDAY'] low = price_data['DISPLAY']['BTC'][fx]['LOWDAY'] market = muted(price_data['DISPLAY']['BTC'][fx]['LASTMARKET']) try: chg = float(chg_str) if chg >= 0: chg_str = success('+' + chg_str + '%') elif chg < 0: chg_str = error(chg_str + '%') except Exception: chg_str = muted(chg_str + '%') if fx == 'USD': btc_usd_price = cleanfloat(price_str) if fx == primary_fx: fx = info(fx) tabs.append( [u' ' + fx, price_str, chg_str, low + ' - ' + high, market]) except Exception as e: tabs.append(['error: ' + str(e)]) tabs = tabulate( tabs, headers=['Fiat', 'Price', '% change', '24h Range', 'Source'], colalign=["center", "right", "right", "center", "right"]) # GBTC gbtc_config = config['STOCKS'] try: if gbtc_config.getboolean('GBTC_enabled'): tabs += '\n\n' gbtc_url = 'https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=GBTC&apikey=DDC232JDH' gbtc_data = tor_request(gbtc_url).json()['Global Quote'] gbtc_tabs = [] GBTC_shares = gbtc_config.getfloat('gbtc_shares') fairvalue, premium = (GBTC_premium(float(gbtc_data['05. price']), btc_usd_price, GBTC_shares)) if premium * 1 > 0: premium = success('+' + jformat(premium, 2, 0.01) + '%') elif premium * 1 < 0: premium = error(jformat(premium, 2, 0.01) + '%') fairvalue = jformat(fairvalue, 2) chg_str = gbtc_data['10. change percent'] try: chg = cleanfloat(chg_str) if chg > 0: chg_str = success('+' + jformat(chg, 2) + ' %') elif chg < 0: chg_str = error(jformat(chg, 2) + ' %') except Exception: chg_str = muted(chg_str) gbtc_tabs.append([ 'GBTC', gbtc_data['05. price'], chg_str, gbtc_data['04. low'] + ' - ' + gbtc_data['03. high'], premium, fairvalue, gbtc_data['07. latest trading day'] ]) gbtc_tabs = tabulate(gbtc_tabs, headers=[ 'Ticker', 'Price', '% change', '24h Range', 'Premium', 'Fair Value', 'Last Update' ], colalign=[ "center", "right", "right", "center", "right", "right", "right" ]) tabs += gbtc_tabs except Exception as e: er_st = error(f' Error getting GBTC data: {e}') tabs += er_st tabs += ( f"\n\n Last Refresh on: {info(datetime.now().strftime('%H:%M:%S'))}") return tabs
def data_mempool(): from node_warden import load_config from node_warden import launch_logger launch_logger() config = load_config(quiet=True) mp_config = config['MEMPOOL'] url = mp_config.get('url') tabs = [] # Get recommended fees mp_fee = tor_request(url + '/api/v1/fees/recommended').json() tabs = list(mp_fee.values()) tabs = [[str(x) + ' sats/Vb' for x in tabs]] tabs = tabulate(tabs, headers=["Fastest Fee", "30 min fee", "1 hour fee"], colalign=["center", "center", "center"]) try: block_height = tor_request(url + '/api/blocks/tip/height').json() except Exception: return (error(f' >> Error getting data from {url}. Retrying...')) # Save the latest block height saved_block = pickle_it(action='load', filename='block.pkl') if (saved_block != block_height) and ( config['MEMPOOL'].getboolean('block_found_sound')): # Block found play sound try: engine = pyttsx3.init() engine.setProperty('rate', 270) engine.say(config['MEMPOOL'].get('block_found_txt')) engine.runAndWait() except Exception: pass logging.info( info('[MEMPOOL] ') + success("A new Bitcoin Block was just found. ") + yellow("'Tick. Tock. Next block.'")) pickle_it(action='save', filename='block.pkl', data=block_height) block_txt = success(f' Block Height: {jformat(block_height, 0)}\n\n') tabs = block_txt + info(' Mempool Fee Estimates: \n') + tabs try: mp_blocks = tor_request(url + '/api/blocks').json() except Exception: return (error(" >> Error getting Mempool data. Retrying...")) mp_tabs = [] gradient_color = 0 for block in mp_blocks: mp_tabs.append([ time_ago(block['timestamp']), jformat(block['height'], 0), jformat(block['tx_count'], 0), jformat(block['size'], 2, 1000000) + ' MB' ]) gradient_color += 1 mp_tabs = tabulate(mp_tabs, headers=[" Time", "Height", "Tx Count", "Size"], colalign=["right", "center", "center", "right"]) tabs += info('\n\n Latest Blocks: \n') + mp_tabs tabs += muted(f"\n\n Source: {url} {success('[Tor Request]')}\n") return tabs
def data_btc_price(): from node_warden import launch_logger launch_logger() from node_warden import load_config config = load_config(quiet=True) fx_config = config['CURRENCIES'] currencies = ast.literal_eval(fx_config.get('fx_list')) primary_fx = ast.literal_eval(fx_config.get('primary_fx')) price_data = multiple_price_grab('BTC', ','.join(currencies)) # Get prices in different currencies tabs = [] btc_usd_price = 0 for fx in currencies: try: price_str = price_data['DISPLAY']['BTC'][fx]['PRICE'] chg_str = price_data['DISPLAY']['BTC'][fx]['CHANGEPCTDAY'] high = price_data['DISPLAY']['BTC'][fx]['HIGHDAY'] low = price_data['DISPLAY']['BTC'][fx]['LOWDAY'] market = muted(price_data['DISPLAY']['BTC'][fx]['LASTMARKET']) try: chg = float(chg_str) if chg >= 0: chg_str = success('+' + chg_str + '%') elif chg < 0: chg_str = error(chg_str + '%') except Exception: chg_str = muted(chg_str + '%') if fx == 'USD': btc_usd_price = cleanfloat(price_str) if fx == primary_fx: fx = info(fx) tabs.append( [u' ' + fx, price_str, chg_str, low + ' - ' + high, market]) except Exception as e: tabs.append(['error: ' + str(e)]) if tabs == []: return ( error(f' >> Error getting data from CryptoCompare. Retrying...')) try: tabs = tabulate( tabs, headers=['Fiat', 'Price', '% change', '24h Range', 'Source'], colalign=["center", "right", "right", "center", "right"]) except Exception: return ( error(f' >> Error getting data from CryptoCompare. Retrying...')) # GBTC gbtc_config = config['STOCKS'] try: if gbtc_config.getboolean('GBTC_enabled'): tabs += '\n\n' gbtc_url = 'https://finnhub.io/api/v1/quote?symbol=GBTC&token=bvfhuqv48v6rhdtvnks0' gbtc_data = tor_request(gbtc_url).json() gbtc_tabs = [] GBTC_shares = gbtc_config.getfloat('gbtc_shares') fairvalue, premium = (GBTC_premium((gbtc_data['c']), btc_usd_price, GBTC_shares)) if premium * 1 > 0: premium = success('+' + jformat(premium, 2, 0.01) + '%') elif premium * 1 < 0: premium = error(jformat(premium, 2, 0.01) + '%') fairvalue = jformat(fairvalue, 2) chg_str = gbtc_data['c'] / gbtc_data['pc'] try: chg = (chg_str) if chg > 0: chg_str = success('+' + jformat(chg, 2) + ' %') elif chg < 0: chg_str = error(jformat(chg, 2) + ' %') except Exception: chg_str = muted(chg_str) gbtc_tabs.append([ 'GBTC', jformat(gbtc_data['c'], 2), chg_str, jformat(gbtc_data['l'], 2) + ' - ' + jformat(gbtc_data['h'], 2), premium, fairvalue, time_ago(gbtc_data['t']) ]) gbtc_tabs = tabulate(gbtc_tabs, headers=[ 'Ticker', 'Price', '% change', '24h Range', 'Premium', 'Fair Value', 'Last Update' ], colalign=[ "center", "right", "right", "center", "right", "right", "right" ]) tabs += gbtc_tabs except Exception as e: er_st = error(f' Error getting GBTC data: {e}') tabs += er_st tabs += ( f"\n\n Last Refresh on: {info(datetime.now().strftime('%H:%M:%S'))}") return tabs