From 26a20afe59838439db9476e17f8a2b8c37ed5640 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 20:23:05 +0100 Subject: [PATCH 01/16] Update LimitSwap.py --- LimitSwap.py | 909 +++++++++++++++++++++++++++------------------------ 1 file changed, 473 insertions(+), 436 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index ab783fe..ffc21a3 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from web3 import Web3 from time import sleep, time import json @@ -9,26 +10,11 @@ import sys import requests import cryptocode, re, pwinput -import argparse -import signal - -# DEVELOPER CONSIDERATIONS -# -# USER INTERACTION - Do not depend on user interaction. If you develop a setting that is going to require -# user interaction while the bot is running, warn the user before hand. Accept a value before the check -# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's -# entire process from buying all the way to selling multiple positions and multiple pairs with zero user -# interaction. -# -# HANDLING NEW ENTRIES IN settings.json - When adding a new configuration item in settings.json be sure to -# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file. -# Do not assume a user has changed their settings.json file to work with the new version, your additions -# should be backwards compatible and have safe default values if possible -# -# HANDLING NEW ENTRIES IN tokens.json - When adding a new configuration item in tokens.json be sure to -# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file -# Do not assume a user has changed their tokens.json file to work with the new version, your additions -# should be backwards compatible and have safe default values if possible + +# global used to track if any settings need to be written to file +settings_changed = False + +failedtransactionsamount = 0 # color styles @@ -44,156 +30,20 @@ class style(): # Class of different text colours - default is white UNDERLINE = '\033[4m' RESET = '\033[0m' -# Function to cleanly exit on SIGINT -def signal_handler(sig, frame): - sys.exit(0) -signal.signal(signal.SIGINT, signal_handler) def timestamp(): timestamp = time() dt_object = datetime.fromtimestamp(timestamp) return dt_object -# -# COMMAND LINE ARGUMENTS -# - -parser = argparse.ArgumentParser() -parser.add_argument("-p", "--password", type=str, help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") -parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", default="./settings.json") -parser.add_argument("-t", "--tokens" , type=str, help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") -parser.add_argument("-v", "--verbose" , action='store_true', help="Print detailed messages to stdout") -command_line_args = parser.parse_args() - -def printt(*print_args): - # Function: printt - # ---------------------------- - # provides normal print() functionality but also prints our timestamp - # - # returns: nothing - - print(timestamp(),' '.join(map(str,print_args))) - -def printt_v(*print_args): - # Function: printt - # ---------------------------- - # provides normal print() functionality but also prints our timestamp and pays attention to user set verbosity. - # - # returns: nothing - - if command_line_args.verbose == True: - print(timestamp(),' '.join(map(str,print_args))) - -def printt_err(*print_args): - # Function: printt_err - # -------------------- - # provides normal print() functionality but also prints our timestamp and the text highlighted to display an error - # - # returns: nothing - - print(timestamp(), " ", style.RED, ' '.join(map(str,print_args)), style.RESET, sep="") - -def load_settings_file(settings_path, load_message = True): - # Function: load_settings_file - # ---------------------------- - # loads the settings file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file - # exits with an error message if necessary variables are not found in the settings files - # - # settings_path = the path of the file to load settings from - # - # returns: a dictionary with the settings from the file loaded - - if load_message == True: - print(timestamp(), "Loading settings from", command_line_args.settings) - - f = open(command_line_args.settings, ) - settings = json.load(f)[0] - f.close() - - for default_false in ['UNLIMITEDSLIPPAGE', 'USECUSTOMNODE']: - if default_false not in settings: - printt_v (default_false, "not found in settings configuration file, settings a default value of false.") - settings[default_false] = "false" - else: - settings[default_false] = settings[default_false].lower() - - for default_true in ['PREAPPROVE']: - if default_true not in settings: - printt_v (default_true, "not found in settings configuration file, settings a default value of true.") - settings[default_true] = "true" - else: - settings[default_true] = settings[default_true].lower() - - # Keys that must be set - for required_key in ['EXCHANGE']: - if required_key not in settings: - printt_err (required_key, "not found in settings configuration file.") - exit (-1) - else: - settings[required_key] = settings[required_key].lower() - - return settings - -def load_tokens_file(tokens_path, load_message = True): - # Function: load_tokens_File - # ---------------------------- - # loads the token definition file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file - # exits with an error message if necessary variables are not found in the settings files - # - # tokens_path: the path of the file to load tokens from - # - # returns: a dictionary with the settings from the file loaded - - if load_message == True: - print(timestamp(), "Loading tokens from", command_line_args.tokens) - - s = open(command_line_args.tokens, ) - tokens = json.load(s) - s.close() - - # Make sure all values are lowercase - for token in tokens: - - for default_false in ['ENABLED', 'LIQUIDITYCHECK', 'LIQUIDITYINNATIVETOKEN', 'USECUSTOMBASEPAIR', 'HASFEES']: - if default_false not in token: - printt_v (default_false, "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a default value of false") - token[default_false] = "false" - else: - token[default_false] = token[default_false].lower() - - - # Keys that must be set - for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE' ]: - if required_key not in token: - printt_err (required_key, "not found in configuration file in configuration for to token", token['SYMBOL']) - exit (-1) - - token_defaults = { - 'SLIPPAGE' : 49, - 'MAXTOKENS' : 0, - 'MOONBAG' : 0, - 'SELLAMOUNTINTOKENS' : 'all', - 'GAS' : 20, - 'BOOSTPERCENT' : 50, - 'GASLIMIT' : 1000000 - - } - - for default_key in token_defaults: - if default_key not in token: - printt_v (default_key , "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a value of", token_defaults['default_key']) - token[default_key] = token_defaults[default_key] - elif default_key == 'SELLAMOUNTINTOKENS': - token_defaults[default_key] = token_defaults[default_key].lower() - - return tokens - """"""""""""""""""""""""""" //PRELOAD """"""""""""""""""""""""""" print(timestamp(), "Preloading Data") -settings = load_settings_file(command_line_args.settings) +f = open('./settings.json', ) +settings = json.load(f)[0] +f.close() directory = './abi/' filename = "standard.json" @@ -240,14 +90,6 @@ def load_tokens_file(tokens_path, load_message = True): """"""""""""""""""""""""""" //ERROR LOGGING """"""""""""""""""""""""""" -os.makedirs('./logs', exist_ok=True) - -if not os.path.exists('./logs/errors.log'): - open('./logs/errors.log', 'w').close() - -if not os.path.exists('./logs/exceptions.log'): - open('./logs/exceptions.log', 'w').close() - log_format = '%(levelname)s: %(asctime)s %(message)s' logging.basicConfig(filename='./logs/errors.log', level=logging.INFO, @@ -393,7 +235,7 @@ def load_tokens_file(tokens_path, load_message = True): base_symbol = "BNB" rugdocchain = '&chain=bsc' modified = False - + elif settings['EXCHANGE'].lower() == 'apeswap': if settings['USECUSTOMNODE'].lower() == 'true': my_provider = settings['CUSTOMNODE'] @@ -563,13 +405,7 @@ def load_tokens_file(tokens_path, load_message = True): def get_password(): - # Function: get_password - # ---------------------------- - # Handles the decision making logic concerning private key encryption and asking the user for their password. - # - # returns: the user's password - - settings_changed = False + global settings_changed setnewpassword = False # Check to see if the user has a version of the settings file before private key encryption existed @@ -577,7 +413,7 @@ def get_password(): response = "" settings_changed = True while response != "y" and response != "n": - print ("\nWould you like to use a password to encrypt your private keys?") + print("\nWould you like to use a password to encrypt your private keys?") response = input("You will need to input this password each time LimitSwap is executed (y/n): ") if response == "y": @@ -588,7 +424,7 @@ def get_password(): # If the user wants to encrypt their private keys, but we don't have an encrypted private key recorded, we need to ask for a password elif settings['ENCRYPTPRIVATEKEYS'] == "true" and not settings['PRIVATEKEY'].startswith('aes:'): - print ("\nPlease create a password to encrypt your private keys.") + print("\nPlease create a password to encrypt your private keys.") setnewpassword = True # Set a new password when necessary @@ -600,34 +436,28 @@ def get_password(): pwd2 = pwinput.pwinput(prompt="\nType your new password again: ") if pwd != pwd2: - print ("Error, password mismatch. Try again.") + print("Error, password mismatch. Try again.") else: passwords_differ = False # The user already has encrypted private keys. Accept a password so we can unencrypt them elif settings['ENCRYPTPRIVATEKEYS'] == "true": - if command_line_args.password: - pwd = command_line_args.password - else: - pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") + pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") else: pwd = "" if not pwd.strip(): - print () - print ("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") - print ("X You are running LimitSwap without encrypting your private keys. X") - print ("X Private keys are stored on disk unencrypted and can be accessed by X") - print ("X anyone with access to the file system, including the Systems/VPS administrator X") - print ("X and anyone with physical access to the machine or hard drives. X") - print ("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") - print () + print() + print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") + print("X You are running LimitSwap without encrypting your private keys. X") + print("X Private keys are stored on disk unencrypted and can be accessed by X") + print("X anyone with access to the file system, including the Systems/VPS administrator X") + print("X and anyone with physical access to the machine or hard drives. X") + print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") + print() - if settings_changed == True: - save_settings(settings, pwd) - return pwd @@ -652,9 +482,12 @@ def get_password(): "APPROVE_FAILED": (style.RED + '\nRUGDOC API RESULT : APPROVE_FAILED \n' '/!\ /!\ /!\ Failed to approve the token.\n This is very likely a honeypot.'), "SWAP_FAILED": (style.RED + '\nRUGDOC API RESULT : SWAP_FAILED \n' - '/!\ /!\ /!\ Failed to sell the token. \n This is very likely a honeypot.') + '/!\ /!\ /!\ Failed to sell the token. \n This is very likely a honeypot.'), + "chain not found": (style.RED + '\nRUGDOC API RESULT : chain not found \n' + '/!\ Sorry, rugdoc API does not work on this chain... (it does not work on ETH, mainly) \n') } + # Function to check rugdoc API def honeypot_check(address): url = (honeypot_url + address + rugdocchain) @@ -662,39 +495,35 @@ def honeypot_check(address): return requests.get(url) -def save_settings(settings, pwd): +def save_settings(pwd): + global settings_changed if len(pwd) > 0: encrypted_settings = settings.copy() - encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) + encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], + pwd) encrypted_settings['PRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['PRIVATEKEY'], pwd) - # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our - # settings.json output so that it's reasable. This should probably be fixed by us importing - # the entire json file, instead of just the [0] element. - - print (timestamp(), "Writing settings to file.") + # MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our + # settings.json output so that it's reasable. This should probably be fixed by us importing + # the entire json file, instead of just the [0] element. + if settings_changed == True: + print(timestamp(), "Writing settings to file.") - if settings['ENCRYPTPRIVATEKEYS'] == "true": - output_settings = encrypted_settings - else: - output_settings = settings + if settings['ENCRYPTPRIVATEKEYS'] == "true": + output_settings = encrypted_settings + else: + output_settings = settings - with open(command_line_args.settings, 'w') as f: - f.write("[\n") - f.write(json.dumps(output_settings, indent=4)) - f.write("\n]\n") + with open('settings.json', 'w') as f: + f.write("[\n") + f.write(json.dumps(output_settings, indent=4)) + f.write("\n]\n") -def parse_wallet_settings(settings, pwd): - # Function: load_wallet_settings - # ---------------------------- - # Handles the process of deciding whether or not the user's private key needs to be decrypted - # Accepts user input for new private keys and wallet addresses - # - # returns: none (exits on incorrect password) - - settings_changed = False +def load_wallet_settings(pwd): + global settings + global settings_changed # Check for limit wallet information if " " in settings['LIMITWALLETADDRESS'] or settings['LIMITWALLETADDRESS'] == "": @@ -709,15 +538,15 @@ def parse_wallet_settings(settings, pwd): # If the limit wallet private key is already set and encrypted, decrypt it elif settings['LIMITWALLETPRIVATEKEY'].startswith('aes:'): - printt("Decrypting limit wallet private key.") + print(timestamp(), "Decrypting limit wallet private key.") settings['LIMITWALLETPRIVATEKEY'] = settings['LIMITWALLETPRIVATEKEY'].replace('aes:', "", 1) settings['LIMITWALLETPRIVATEKEY'] = cryptocode.decrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) if settings['LIMITWALLETPRIVATEKEY'] == False: - printt_err("ERROR: User provided an invalid password for private key decryption.") - print(style.RED + "\nERROR: Your private key decryption password is incorrect") - print(style.RESET + "Please re-launch the bot and try again\n") - exit(-1) + print(style.RED + "ERROR: Your private key decryption password is incorrect") + print(style.RESET + "Please re-launch the bot and try again") + sleep(10) + sys.exit() # Check for trading wallet information if " " in settings['WALLETADDRESS'] or settings['WALLETADDRESS'] == "": @@ -731,15 +560,10 @@ def parse_wallet_settings(settings, pwd): # If the trading wallet private key is already set and encrypted, decrypt it elif settings['PRIVATEKEY'].startswith('aes:'): - print (timestamp(), "Decrypting limit wallet private key.") + print(timestamp(), "Decrypting limit wallet private key.") settings['PRIVATEKEY'] = settings['PRIVATEKEY'].replace('aes:', "", 1) settings['PRIVATEKEY'] = cryptocode.decrypt(settings['PRIVATEKEY'], pwd) - if settings_changed == True: - save_settings(settings, pwd) - - - def decimals(address): try: @@ -852,8 +676,7 @@ def approve(address, amount): exit() contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) - transaction = contract.functions.approve(routerAddress, amount - ).buildTransaction({ + transaction = contract.functions.approve(routerAddress, amount).buildTransaction({ 'gasPrice': Web3.toWei(gas, 'gwei'), 'gas': 300000, 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), @@ -878,7 +701,7 @@ def approve(address, amount): return tx_hash else: print(timestamp(), - style.RED + "You have less than 0.01 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet." + style.RESET) + "You have less than 0.01 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") logging.info( "You have less than 0.01 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) @@ -890,16 +713,20 @@ def check_approval(address, balance): contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) allowance = contract.functions.allowance(Web3.toChecksumAddress(settings['WALLETADDRESS']), routerAddress).call() - if allowance < balance: + print("debut allowance:", allowance) + print("debut balance:", balance) + sleep(10) + + if int(allowance) < int(balance): if settings["EXCHANGE"].lower() == 'quickswap': print("Revert to Zero To change approval") tx = approve(address, 0) wait_for_tx(tx, address, False) - tx = approve(address, balance) + tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) wait_for_tx(tx, address, False) else: - tx = approve(address, balance) + tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) wait_for_tx(tx, address, False) return @@ -949,7 +776,7 @@ def check_pool(inToken, outToken, symbol): return pooled -def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase): +def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase, sellpriceinbase): # CHECK GET RATE OF THE TOKEn DECIMALS = decimals(inToken) @@ -965,26 +792,26 @@ def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth, outToken]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base) + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) else: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) else: if outToken != weth: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, outToken]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base) + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) else: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) return tokenPrice @@ -1017,7 +844,6 @@ def wait_for_tx(tx_hash, address, check): sleep(5) break - # loop to check for balance after purchase if check == True: timeout = time() + 30 @@ -1050,14 +876,14 @@ def preapprove(tokens): 115792089237316195423570985008687907853269984665640564039457584007913129639934) -def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, failedtransactionsnumber): - +def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, + failedtransactionsnumber): seconds = int(waitseconds) if int(failedtransactionsamount) == int(failedtransactionsnumber): - print(style.RED + "\n ---------------------------------------------------------------\n" - " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" - " ---------------------------------------------------------------\n\n") - + print( + style.RED + "\n ---------------------------------------------------------------\n" + " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" + " ---------------------------------------------------------------\n\n") logging.info("Bot has reached maximum FAILED TRANSACTIONS number: it stops") sleep(10) @@ -1071,7 +897,8 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, print(timestamp(), "Placing New Buy Order for " + symbol) if int(gaslimit) < 250000: - print("Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") + print( + "Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") gaslimit = 300000 if custom.lower() == 'false': @@ -1097,6 +924,7 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, amount = int(float(amount) * DECIMALS) if custom.lower() == 'false': + # if USECUSTOMBASEPAIR = false amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': min_tokens = 100 @@ -1105,7 +933,8 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, deadline = int(time() + + 60) - # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED + # THIS SECTION IS FOR MODIFIED CONTRACTS : EACH EXCHANGE NEEDS TO BE SPECIFIED + # USECUSTOMBASEPAIR = false if modified == True: if settings["EXCHANGE"].lower() == 'koffeeswap': @@ -1138,38 +967,28 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, else: - # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED - if modified == True: + # USECUSTOMBASEPAIR = false + # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. - if settings["EXCHANGE"].lower() == 'koffeeswap': - transaction = routerContract.functions.swapExactKCSForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'value': amount, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': - transaction = routerContract.functions.swapExactAVAXForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'value': amount, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # Special condition on Uniswap, to implement EIP-1559 + if settings["EXCHANGE"].lower() == 'uniswap': + transaction = routerContract.functions.swapExactETHForTokens( + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) else: + # USECUSTOMBASEPAIR = false + # for all the rest of exchanges with Modified = false transaction = routerContract.functions.swapExactETHForTokens( min_tokens, [weth, outToken], @@ -1184,8 +1003,10 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, }) else: - + # USECUSTOMBASEPAIR = true if inToken == weth: + # USECUSTOMBASEPAIR = true + # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': min_tokens = 100 @@ -1193,53 +1014,28 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, min_tokens = int(amount_out * (1 - (slippage / 100))) deadline = int(time() + + 60) - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - else: - - if routing.lower() == 'true': - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[-1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 transaction = routerContract.functions.swapExactTokensForTokens( amount, min_tokens, - [inToken, weth, outToken], + [weth, outToken], Web3.toChecksumAddress(settings['WALLETADDRESS']), deadline ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), 'gas': gaslimit, 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" }) else: - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - transaction = routerContract.functions.swapExactTokensForTokens( amount, min_tokens, - [inToken, outToken], + [weth, outToken], Web3.toChecksumAddress(settings['WALLETADDRESS']), deadline ).buildTransaction({ @@ -1249,6 +1045,111 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) }) + else: + # LIQUIDITYINNATIVETOKEN = true + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + if routing.lower() == 'true': + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[ + -1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if settings["EXCHANGE"].lower() == 'uniswap': + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # LIQUIDITYINNATIVETOKEN = true + + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # LIQUIDITYINNATIVETOKEN = true + # Exchange different from Uniswap + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if settings["EXCHANGE"].lower() == 'uniswap': + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # Special condition on Uniswap, to implement EIP-1559 + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # Exchange different from Uniswap + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + sync(inToken, outToken) signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) @@ -1277,7 +1178,7 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, routing): print(timestamp(), "Placing Sell Order " + symbol) balance = Web3.fromWei(check_balance(inToken, symbol), 'ether') - check_approval(inToken, balance) + check_approval(inToken, balance*1000000000) if int(gaslimit) < 250000: gaslimit = 300000 @@ -1304,12 +1205,10 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee balance = check_balance(inToken, symbol) moonbag = int(Decimal(moonbag) * DECIMALS) amount = int(Decimal(balance - moonbag)) - print("debug 1036 amount ALL:", amount) else: balance = check_balance(inToken, symbol) amount = Decimal(amount) * DECIMALS - print("debug 1040 amount:", amount) moonbag = int(Decimal(moonbag) * DECIMALS) if balance < amount: @@ -1324,6 +1223,7 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee amount = 0 if custom.lower() == 'false': + # USECUSTOMBASEPAIR = false sync(inToken, weth) amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] @@ -1334,6 +1234,8 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED if modified == True: + # USECUSTOMBASEPAIR = false + # HASFEES = true if settings["EXCHANGE"].lower() == 'koffeeswap': transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( @@ -1364,6 +1266,9 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee }) else: + # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. + # USECUSTOMBASEPAIR = false + # HASFEES = true transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( amount, min_tokens, @@ -1377,9 +1282,14 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) }) else: + # USECUSTOMBASEPAIR = false + # HASFEES = false # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED if modified == True: + # USECUSTOMBASEPAIR = false + # HASFEES = false + # Modified = true if settings["EXCHANGE"].lower() == 'koffeeswap': transaction = routerContract.functions.swapExactTokensForKCS( @@ -1409,34 +1319,63 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee }) else: - transaction = routerContract.functions.swapExactTokensForETH( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # USECUSTOMBASEPAIR = false + # HASFEES = false + # Modified = false --> uniswap / pancakeswap / apeswap, etc. - else: + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForETH( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + else: + # for all the rest of exchanges with Modified = false + transaction = routerContract.functions.swapExactTokensForETH( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # USECUSTOMBASEPAIR = true if outToken == weth: + # if user has set WETH or WBNB as Custom base pair sync(inToken, outToken) amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] min_tokens = int(amount_out * (1 - (slippage / 100))) deadline = int(time() + + 60) if fees.lower() == 'true': + # USECUSTOMBASEPAIR = true + # HASFEES = true if int(gaslimit) < 950000: gaslimit = 950000 # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED if modified == True: + # USECUSTOMBASEPAIR = true + # HASFEES = true + # Modified = true if settings["EXCHANGE"].lower() == 'koffeeswap': transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( @@ -1467,6 +1406,10 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee }) else: + # USECUSTOMBASEPAIR = true + # HASFEES = true + # Modified = false + transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( amount, min_tokens, @@ -1480,6 +1423,8 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) }) else: + # USECUSTOMBASEPAIR = true + # HASFEES = false transaction = routerContract.functions.swapExactTokensForTokens( amount, min_tokens, @@ -1498,38 +1443,88 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee sync(inToken, outToken) if routing.lower() == 'false' and outToken != weth: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] min_tokens = int(amount_out * (1 - (slippage / 100))) deadline = int(time() + + 60) if fees.lower() == 'true': - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # HASFEES = true + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # for all the rest of exchanges + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + else: - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # HASFEES = false + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # for all the rest of exchanges + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) elif routing.lower() == 'false' and outToken == weth: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address print( "ERROR IN YOUR TOKENS.JSON : YOU NEED TO CHOOSE THE PROPER BASE PAIR AS SYMBOL IF YOU ARE TRADING OUTSIDE OF NATIVE LIQUIDITY POOL") @@ -1539,31 +1534,69 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee deadline = int(time() + + 60) if fees.lower() == 'true': - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # HASFEES = true + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + else: - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) + # HASFEES = false + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + else: + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) sync(inToken, outToken) signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) @@ -1588,20 +1621,22 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee def run(): - global failedtransactionsamount try: - - tokens = load_tokens_file(command_line_args.tokens, True) + s = open('./tokens.json', ) + tokens = json.load(s) + s.close() eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') if eth_balance > 0.05: pass else: - print(style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet" + style.RESET) - logging.info("You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + print( + style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") + logging.info( + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) sys.exit() @@ -1610,15 +1645,7 @@ def run(): else: pass - for token in tokens: - - if 'RUGDOC_CHECK' not in token: - token['RUGDOC_CHECK'] = 'false' - if 'BUYAFTER_XXX_SECONDS' not in token: - token['BUYAFTER_XXX_SECONDS'] = 0 - if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 if token['RUGDOC_CHECK'].lower() == 'true': @@ -1632,11 +1659,11 @@ def run(): decision = "" while decision != "y" and decision != "n": - print (style.RESET + "\nWhat is your decision?") + print(style.RESET + "\nWhat is your decision?") decision = input("Would you like to snipe this token? (y/n): ") if decision == "y": - print (style.RESET + "\nOK let's go!!\n") + print(style.RESET + "\nOK let's go!!\n") pass else: sys.exit() @@ -1645,18 +1672,12 @@ def run(): pass while True: - - tokens = load_tokens_file(command_line_args.tokens, False) + s = open('./tokens.json', ) + tokens = json.load(s) + s.close() for token in tokens: - if 'RUGDOC_CHECK' not in token: - token['RUGDOC_CHECK'] = 'false' - if 'BUYAFTER_XXX_SECONDS' not in token: - token['BUYAFTER_XXX_SECONDS'] = 0 - if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 - if token['ENABLED'].lower() == 'true': inToken = Web3.toChecksumAddress(token['ADDRESS']) @@ -1668,7 +1689,7 @@ def run(): try: quote = check_price(inToken, outToken, token['SYMBOL'], token['BASESYMBOL'], token['USECUSTOMBASEPAIR'], token['LIQUIDITYINNATIVETOKEN'], - token['BUYPRICEINBASE']) + token['BUYPRICEINBASE'], token['SELLPRICEINBASE']) pool = check_pool(inToken, outToken, token['BASESYMBOL']) # print("Debug Liquidity Reserves ligne 1267:", float(pool)) # print("Debug inToken : ", inToken, "outToken :", outToken) @@ -1697,13 +1718,15 @@ def run(): tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], - token['BASESYMBOL'], token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + token['BASESYMBOL'], token['LIQUIDITYINNATIVETOKEN'], + token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) if tx != False: tx = wait_for_tx(tx, token['ADDRESS'], True) - print(style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") print(style.RESET + "") sleep(3) check_balance(token['ADDRESS'], token['SYMBOL']) @@ -1713,20 +1736,21 @@ def run(): if tx != 1: # transaction is a FAILURE print( - style.RED + "\n -------------------------------------------------\n" - " FAILURE ! Plese check your wallet. \n" - " Cause of failure can be : \n" - " - GASLIMIT too low\n" - " - SLIPPAGE too low\n" - " -------------------------------------------------\n\n") + style.RED + "\n -------------------------------------------------\n" + " FAILURE ! Plese check your wallet. \n" + " Cause of failure can be : \n" + " - GASLIMIT too low\n" + " - SLIPPAGE too low\n" + " -------------------------------------------------\n\n") print(style.RESET + "") failedtransactionsamount += 1 preapprove(tokens) else: # transaction is a SUCCESS - print(style.GREEN + "\n ----------------------------------\n" - " SUCCESS : your Tx is confirmed :)\n" - " ----------------------------------\n") + print( + style.GREEN + "\n ----------------------------------\n" + " SUCCESS : your Tx is confirmed :)\n" + " ----------------------------------\n") print(style.RESET + "") pass @@ -1744,13 +1768,15 @@ def run(): tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['BASESYMBOL'], - token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) if tx != False: tx = wait_for_tx(tx, token['ADDRESS'], True) - print(style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") print(style.RESET + "") sleep(3) check_balance(token['ADDRESS'], token['SYMBOL']) @@ -1759,20 +1785,22 @@ def run(): if tx != 1: # transaction is a FAILURE - print(style.RED + "\n -------------------------------------------------\n" - " FAILURE ! Please check your wallet. \n" - " Cause of failure can be : \n" - " - GASLIMIT too low\n" - " - SLIPPAGE too low\n" - " -------------------------------------------------\n\n") + print( + style.RED + "\n -------------------------------------------------\n" + " FAILURE ! Please check your wallet. \n" + " Cause of failure can be : \n" + " - GASLIMIT too low\n" + " - SLIPPAGE too low\n" + " -------------------------------------------------\n\n") print(style.RESET + "") failedtransactionsamount += 1 preapprove(tokens) else: # transaction is a SUCCESS - print(style.GREEN + "\n ----------------------------------\n" - " SUCCESS : your Tx is confirmed :)\n" - " ----------------------------------\n") + print( + style.GREEN + "\n ----------------------------------\n" + " SUCCESS : your Tx is confirmed :)\n" + " ----------------------------------\n") print(style.RESET + "") pass else: @@ -1782,7 +1810,7 @@ def run(): else: print( - timestamp(), "You own more tokens than your MAXTOKENS parameter for ", token['SYMBOL']) + timestamp(), "You own more tokens than your MAXTOKENS parameter for ", token['SYMBOL']) if quote > Decimal(token['SELLPRICEINBASE']): DECIMALS = decimals(inToken) @@ -1799,6 +1827,12 @@ def run(): token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['LIQUIDITYINNATIVETOKEN']) wait_for_tx(tx, token['ADDRESS'], False) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + sleep(5) + print(style.RESET + "") else: pass @@ -1817,6 +1851,13 @@ def run(): token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['LIQUIDITYINNATIVETOKEN']) wait_for_tx(tx, token['ADDRESS'], False) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + sleep(5) + print(style.RESET + "") + else: # Double Check For Buy if Sell Signal Triggers if quote < Decimal(token['BUYPRICEINBASE']): @@ -1828,7 +1869,8 @@ def run(): tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], - token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) wait_for_tx(tx, token['ADDRESS'], False) else: print(timestamp(), "Bot has reached MAXTOKENS Position Size for ", token['SYMBOL']) @@ -1859,15 +1901,10 @@ def run(): try: check_logs() - - # Get the user password on first run userpassword = get_password() - - # Handle any proccessing that is necessary to load the private key for the wallet - parse_wallet_settings(settings, userpassword) - - # The LIMIT balance of the user. + load_wallet_settings(userpassword) true_balance = auth() + save_settings(userpassword) version = 3.36 logging.info("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) From e505d98c2c3b0b58239f9319d8e0b170b27b38dc Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 21:35:56 +0100 Subject: [PATCH 02/16] Update LimitSwap.py --- LimitSwap.py | 239 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 210 insertions(+), 29 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index ffc21a3..8c51ac2 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -10,10 +10,29 @@ import sys import requests import cryptocode, re, pwinput - -# global used to track if any settings need to be written to file -settings_changed = False - +import argparse +import signal + +# DEVELOPER CONSIDERATIONS +# +# USER INTERACTION - Do not depend on user interaction. If you develop a setting that is going to require +# user interaction while the bot is running, warn the user before hand. Accept a value before the check +# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's +# entire process from buying all the way to selling multiple positions and multiple pairs with zero user +# interaction. +# +# HANDLING NEW ENTRIES IN settings.json - When adding a new configuration item in settings.json be sure to +# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file. +# Do not assume a user has changed their settings.json file to work with the new version, your additions +# should be backwards compatible and have safe default values if possible +# +# HANDLING NEW ENTRIES IN tokens.json - When adding a new configuration item in tokens.json be sure to +# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file +# Do not assume a user has changed their tokens.json file to work with the new version, your additions +# should be backwards compatible and have safe default values if possible + + +# initialization of number of failed transactions failedtransactionsamount = 0 @@ -29,21 +48,157 @@ class style(): # Class of different text colours - default is white WHITE = '\033[37m' UNDERLINE = '\033[4m' RESET = '\033[0m' - + +# Function to cleanly exit on SIGINT +def signal_handler(sig, frame): + sys.exit(0) +signal.signal(signal.SIGINT, signal_handler) def timestamp(): timestamp = time() dt_object = datetime.fromtimestamp(timestamp) return dt_object +# +# COMMAND LINE ARGUMENTS +# + +parser = argparse.ArgumentParser() +parser.add_argument("-p", "--password", type=str, help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") +parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", default="./settings.json") +parser.add_argument("-t", "--tokens" , type=str, help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") +parser.add_argument("-v", "--verbose" , action='store_true', help="Print detailed messages to stdout") +command_line_args = parser.parse_args() + +def printt(*print_args): + # Function: printt + # ---------------------------- + # provides normal print() functionality but also prints our timestamp + # + # returns: nothing + + print(timestamp(),' '.join(map(str,print_args))) + +def printt_v(*print_args): + # Function: printt + # ---------------------------- + # provides normal print() functionality but also prints our timestamp and pays attention to user set verbosity. + # + # returns: nothing + + if command_line_args.verbose == True: + print(timestamp(),' '.join(map(str,print_args))) + +def printt_err(*print_args): + # Function: printt_err + # -------------------- + # provides normal print() functionality but also prints our timestamp and the text highlighted to display an error + # + # returns: nothing + + print(timestamp(), " ", style.RED, ' '.join(map(str,print_args)), style.RESET, sep="") + +def load_settings_file(settings_path, load_message = True): + # Function: load_settings_file + # ---------------------------- + # loads the settings file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file + # exits with an error message if necessary variables are not found in the settings files + # + # settings_path = the path of the file to load settings from + # + # returns: a dictionary with the settings from the file loaded + + if load_message == True: + print(timestamp(), "Loading settings from", command_line_args.settings) + + f = open(command_line_args.settings, ) + settings = json.load(f)[0] + f.close() + + for default_false in ['UNLIMITEDSLIPPAGE', 'USECUSTOMNODE']: + if default_false not in settings: + printt_v (default_false, "not found in settings configuration file, settings a default value of false.") + settings[default_false] = "false" + else: + settings[default_false] = settings[default_false].lower() + + for default_true in ['PREAPPROVE']: + if default_true not in settings: + printt_v (default_true, "not found in settings configuration file, settings a default value of true.") + settings[default_true] = "true" + else: + settings[default_true] = settings[default_true].lower() + + # Keys that must be set + for required_key in ['EXCHANGE']: + if required_key not in settings: + printt_err (required_key, "not found in settings configuration file.") + exit (-1) + else: + settings[required_key] = settings[required_key].lower() + + return settings + +def load_tokens_file(tokens_path, load_message = True): + # Function: load_tokens_File + # ---------------------------- + # loads the token definition file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file + # exits with an error message if necessary variables are not found in the settings files + # + # tokens_path: the path of the file to load tokens from + # + # returns: a dictionary with the settings from the file loaded + + if load_message == True: + print(timestamp(), "Loading tokens from", command_line_args.tokens) + + s = open(command_line_args.tokens, ) + tokens = json.load(s) + s.close() + + # Make sure all values are lowercase + for token in tokens: + + for default_false in ['ENABLED', 'LIQUIDITYCHECK', 'LIQUIDITYINNATIVETOKEN', 'USECUSTOMBASEPAIR', 'HASFEES']: + if default_false not in token: + printt_v (default_false, "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a default value of false") + token[default_false] = "false" + else: + token[default_false] = token[default_false].lower() + + + # Keys that must be set + for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE' ]: + if required_key not in token: + printt_err (required_key, "not found in configuration file in configuration for to token", token['SYMBOL']) + exit (-1) + + token_defaults = { + 'SLIPPAGE' : 49, + 'MAXTOKENS' : 0, + 'MOONBAG' : 0, + 'SELLAMOUNTINTOKENS' : 'all', + 'GAS' : 20, + 'BOOSTPERCENT' : 50, + 'GASLIMIT' : 1000000 + + } + + for default_key in token_defaults: + if default_key not in token: + printt_v (default_key , "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a value of", token_defaults['default_key']) + token[default_key] = token_defaults[default_key] + elif default_key == 'SELLAMOUNTINTOKENS': + token_defaults[default_key] = token_defaults[default_key].lower() + + return tokens + """"""""""""""""""""""""""" //PRELOAD """"""""""""""""""""""""""" print(timestamp(), "Preloading Data") -f = open('./settings.json', ) -settings = json.load(f)[0] -f.close() +settings = load_settings_file(command_line_args.settings) directory = './abi/' filename = "standard.json" @@ -90,6 +245,14 @@ def timestamp(): """"""""""""""""""""""""""" //ERROR LOGGING """"""""""""""""""""""""""" +os.makedirs('./logs', exist_ok=True) + +if not os.path.exists('./logs/errors.log'): + open('./logs/errors.log', 'w').close() + +if not os.path.exists('./logs/exceptions.log'): + open('./logs/exceptions.log', 'w').close() + log_format = '%(levelname)s: %(asctime)s %(message)s' logging.basicConfig(filename='./logs/errors.log', level=logging.INFO, @@ -405,7 +568,13 @@ def timestamp(): def get_password(): - global settings_changed + # Function: get_password + # ---------------------------- + # Handles the decision making logic concerning private key encryption and asking the user for their password. + # + # returns: the user's password + + settings_changed = False setnewpassword = False # Check to see if the user has a version of the settings file before private key encryption existed @@ -443,8 +612,11 @@ def get_password(): # The user already has encrypted private keys. Accept a password so we can unencrypt them elif settings['ENCRYPTPRIVATEKEYS'] == "true": - pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") - + if command_line_args.password: + pwd = command_line_args.password + else: + pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") + else: pwd = "" @@ -457,6 +629,9 @@ def get_password(): print("X and anyone with physical access to the machine or hard drives. X") print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") print() + + if settings_changed == True: + save_settings(settings, pwd) return pwd @@ -495,36 +670,40 @@ def honeypot_check(address): return requests.get(url) -def save_settings(pwd): - global settings_changed - +def save_settings(settings, pwd): + if len(pwd) > 0: encrypted_settings = settings.copy() encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) encrypted_settings['PRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['PRIVATEKEY'], pwd) - # MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our + # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our # settings.json output so that it's reasable. This should probably be fixed by us importing # the entire json file, instead of just the [0] element. - if settings_changed == True: - print(timestamp(), "Writing settings to file.") + print(timestamp(), "Writing settings to file.") - if settings['ENCRYPTPRIVATEKEYS'] == "true": - output_settings = encrypted_settings - else: - output_settings = settings + if settings['ENCRYPTPRIVATEKEYS'] == "true": + output_settings = encrypted_settings + else: + output_settings = settings - with open('settings.json', 'w') as f: - f.write("[\n") - f.write(json.dumps(output_settings, indent=4)) - f.write("\n]\n") + with open(command_line_args.settings, 'w') as f: + f.write("[\n") + f.write(json.dumps(output_settings, indent=4)) + f.write("\n]\n") -def load_wallet_settings(pwd): - global settings - global settings_changed +def parse_wallet_settings(settings, pwd): + # Function: load_wallet_settings + # ---------------------------- + # Handles the process of deciding whether or not the user's private key needs to be decrypted + # Accepts user input for new private keys and wallet addresses + # + # returns: none (exits on incorrect password) + settings_changed = False + # Check for limit wallet information if " " in settings['LIMITWALLETADDRESS'] or settings['LIMITWALLETADDRESS'] == "": settings_changed = True @@ -538,7 +717,7 @@ def load_wallet_settings(pwd): # If the limit wallet private key is already set and encrypted, decrypt it elif settings['LIMITWALLETPRIVATEKEY'].startswith('aes:'): - print(timestamp(), "Decrypting limit wallet private key.") + printt("Decrypting limit wallet private key.") settings['LIMITWALLETPRIVATEKEY'] = settings['LIMITWALLETPRIVATEKEY'].replace('aes:', "", 1) settings['LIMITWALLETPRIVATEKEY'] = cryptocode.decrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) @@ -564,6 +743,8 @@ def load_wallet_settings(pwd): settings['PRIVATEKEY'] = settings['PRIVATEKEY'].replace('aes:', "", 1) settings['PRIVATEKEY'] = cryptocode.decrypt(settings['PRIVATEKEY'], pwd) + if settings_changed == True: + save_settings(settings, pwd) def decimals(address): try: From 9290d81f1f96e758d2936039084093585a899acb Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 21:45:57 +0100 Subject: [PATCH 03/16] Update LimitSwap.py --- LimitSwap.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 8c51ac2..878904e 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -1805,17 +1805,14 @@ def run(): global failedtransactionsamount try: - s = open('./tokens.json', ) - tokens = json.load(s) - s.close() + tokens = load_tokens_file(command_line_args.tokens, True) eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') if eth_balance > 0.05: pass else: - print( - style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") + print(style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") logging.info( "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) @@ -1827,7 +1824,15 @@ def run(): pass for token in tokens: - + # Initialization of values, in case the user re-used some old tokens.json files + if 'RUGDOC_CHECK' not in token: + token['RUGDOC_CHECK'] = 'false' + if 'BUYAFTER_XXX_SECONDS' not in token: + token['BUYAFTER_XXX_SECONDS'] = 0 + if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 + # End of initialization of values + if token['RUGDOC_CHECK'].lower() == 'true': honeypot = honeypot_check(address=token['ADDRESS']) @@ -1853,12 +1858,18 @@ def run(): pass while True: - s = open('./tokens.json', ) - tokens = json.load(s) - s.close() - + tokens = load_tokens_file(command_line_args.tokens, False) + for token in tokens: - + # Initialization of values, in case the user re-used some old tokens.json files + if 'RUGDOC_CHECK' not in token: + token['RUGDOC_CHECK'] = 'false' + if 'BUYAFTER_XXX_SECONDS' not in token: + token['BUYAFTER_XXX_SECONDS'] = 0 + if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 + # End of initialization of values + if token['ENABLED'].lower() == 'true': inToken = Web3.toChecksumAddress(token['ADDRESS']) @@ -1990,8 +2001,7 @@ def run(): else: - print( - timestamp(), "You own more tokens than your MAXTOKENS parameter for ", token['SYMBOL']) + print(timestamp(), "You own more tokens than your MAXTOKENS parameter for ", token['SYMBOL']) if quote > Decimal(token['SELLPRICEINBASE']): DECIMALS = decimals(inToken) @@ -2082,10 +2092,15 @@ def run(): try: check_logs() + + # Get the user password on first run userpassword = get_password() - load_wallet_settings(userpassword) + + # Handle any proccessing that is necessary to load the private key for the wallet + parse_wallet_settings(settings, userpassword) + + # The LIMIT balance of the user. true_balance = auth() - save_settings(userpassword) version = 3.36 logging.info("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) From a8424d76c45c38834d5e66adb4aba32b1e632b55 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 21:57:15 +0100 Subject: [PATCH 04/16] Update LimitSwap.py --- LimitSwap.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 878904e..beae467 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -48,7 +48,7 @@ class style(): # Class of different text colours - default is white WHITE = '\033[37m' UNDERLINE = '\033[4m' RESET = '\033[0m' - + # Function to cleanly exit on SIGINT def signal_handler(sig, frame): sys.exit(0) @@ -252,7 +252,7 @@ def load_tokens_file(tokens_path, load_message = True): if not os.path.exists('./logs/exceptions.log'): open('./logs/exceptions.log', 'w').close() - + log_format = '%(levelname)s: %(asctime)s %(message)s' logging.basicConfig(filename='./logs/errors.log', level=logging.INFO, @@ -616,7 +616,7 @@ def get_password(): pwd = command_line_args.password else: pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") - + else: pwd = "" @@ -671,7 +671,7 @@ def honeypot_check(address): def save_settings(settings, pwd): - + if len(pwd) > 0: encrypted_settings = settings.copy() encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], @@ -681,6 +681,7 @@ def save_settings(settings, pwd): # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our # settings.json output so that it's reasable. This should probably be fixed by us importing # the entire json file, instead of just the [0] element. + print(timestamp(), "Writing settings to file.") if settings['ENCRYPTPRIVATEKEYS'] == "true": @@ -746,6 +747,7 @@ def parse_wallet_settings(settings, pwd): if settings_changed == True: save_settings(settings, pwd) + def decimals(address): try: balanceContract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) @@ -882,9 +884,9 @@ def approve(address, amount): return tx_hash else: print(timestamp(), - "You have less than 0.01 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") logging.info( - "You have less than 0.01 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) sys.exit() @@ -1057,12 +1059,10 @@ def preapprove(tokens): 115792089237316195423570985008687907853269984665640564039457584007913129639934) -def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, - failedtransactionsnumber): +def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, failedtransactionsnumber): seconds = int(waitseconds) if int(failedtransactionsamount) == int(failedtransactionsnumber): - print( - style.RED + "\n ---------------------------------------------------------------\n" + print(style.RED + "\n ---------------------------------------------------------------\n" " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" " ---------------------------------------------------------------\n\n") @@ -1078,8 +1078,7 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, print(timestamp(), "Placing New Buy Order for " + symbol) if int(gaslimit) < 250000: - print( - "Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") + print("Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") gaslimit = 300000 if custom.lower() == 'false': @@ -1802,9 +1801,11 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee def run(): + global failedtransactionsamount try: + tokens = load_tokens_file(command_line_args.tokens, True) eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') @@ -1813,8 +1814,7 @@ def run(): pass else: print(style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") - logging.info( - "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + logging.info("You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) sys.exit() From af034368417e9265630176da0595ecc2e3badcc5 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:01:01 +0100 Subject: [PATCH 05/16] Update LimitSwap.py --- LimitSwap.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index beae467..54c44b4 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -896,10 +896,6 @@ def check_approval(address, balance): contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) allowance = contract.functions.allowance(Web3.toChecksumAddress(settings['WALLETADDRESS']), routerAddress).call() - print("debut allowance:", allowance) - print("debut balance:", balance) - sleep(10) - if int(allowance) < int(balance): if settings["EXCHANGE"].lower() == 'quickswap': From ebe317bf524d6567b5d977640404c9443ee75c5b Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:12:28 +0100 Subject: [PATCH 06/16] Update LimitSwap.py --- LimitSwap.py | 2306 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 2250 insertions(+), 56 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 54c44b4..c334a05 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -17,7 +17,7 @@ # # USER INTERACTION - Do not depend on user interaction. If you develop a setting that is going to require # user interaction while the bot is running, warn the user before hand. Accept a value before the check -# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's +# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's # entire process from buying all the way to selling multiple positions and multiple pairs with zero user # interaction. # @@ -49,27 +49,2209 @@ class style(): # Class of different text colours - default is white UNDERLINE = '\033[4m' RESET = '\033[0m' + +# Function to cleanly exit on SIGINT +def signal_handler(sig, frame): + sys.exit(0) + + +signal.signal(signal.SIGINT, signal_handler) + + +def timestamp(): + timestamp = time() + dt_object = datetime.fromtimestamp(timestamp) + return dt_object + + +# +# COMMAND LINE ARGUMENTS +# + +parser = argparse.ArgumentParser() +parser.add_argument("-p", "--password", type=str, + help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") +parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", + default="./settings.json") +parser.add_argument("-t", "--tokens", type=str, + help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") +parser.add_argument("-v", "--verbose", action='store_true', help="Print detailed messages to stdout") +command_line_args = parser.parse_args() + + +def printt(*print_args): + # Function: printt + # ---------------------------- + # provides normal print() functionality but also prints our timestamp + # + # returns: nothing + + print(timestamp(), ' '.join(map(str, print_args))) + + +def printt_v(*print_args): + # Function: printt + # ---------------------------- + # provides normal print() functionality but also prints our timestamp and pays attention to user set verbosity. + # + # returns: nothing + + if command_line_args.verbose == True: + print(timestamp(), ' '.join(map(str, print_args))) + + +def printt_err(*print_args): + # Function: printt_err + # -------------------- + # provides normal print() functionality but also prints our timestamp and the text highlighted to display an error + # + # returns: nothing + + print(timestamp(), " ", style.RED, ' '.join(map(str, print_args)), style.RESET, sep="") + + +def load_settings_file(settings_path, load_message=True): + # Function: load_settings_file + # ---------------------------- + # loads the settings file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file + # exits with an error message if necessary variables are not found in the settings files + # + # settings_path = the path of the file to load settings from + # + # returns: a dictionary with the settings from the file loaded + + if load_message == True: + print(timestamp(), "Loading settings from", command_line_args.settings) + + f = open(command_line_args.settings, ) + settings = json.load(f)[0] + f.close() + + for default_false in ['UNLIMITEDSLIPPAGE', 'USECUSTOMNODE']: + if default_false not in settings: + printt_v(default_false, "not found in settings configuration file, settings a default value of false.") + settings[default_false] = "false" + else: + settings[default_false] = settings[default_false].lower() + + for default_true in ['PREAPPROVE']: + if default_true not in settings: + printt_v(default_true, "not found in settings configuration file, settings a default value of true.") + settings[default_true] = "true" + else: + settings[default_true] = settings[default_true].lower() + + # Keys that must be set + for required_key in ['EXCHANGE']: + if required_key not in settings: + printt_err(required_key, "not found in settings configuration file.") + exit(-1) + else: + settings[required_key] = settings[required_key].lower() + + return settings + + +def load_tokens_file(tokens_path, load_message=True): + # Function: load_tokens_File + # ---------------------------- + # loads the token definition file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file + # exits with an error message if necessary variables are not found in the settings files + # + # tokens_path: the path of the file to load tokens from + # + # returns: a dictionary with the settings from the file loaded + + if load_message == True: + print(timestamp(), "Loading tokens from", command_line_args.tokens) + + s = open(command_line_args.tokens, ) + tokens = json.load(s) + s.close() + + # Make sure all values are lowercase + for token in tokens: + + for default_false in ['ENABLED', 'LIQUIDITYCHECK', 'LIQUIDITYINNATIVETOKEN', 'USECUSTOMBASEPAIR', 'HASFEES']: + if default_false not in token: + printt_v(default_false, "not found in configuration file in configuration for to token", + token['SYMBOL'], "setting a default value of false") + token[default_false] = "false" + else: + token[default_false] = token[default_false].lower() + + # Keys that must be set + for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE']: + if required_key not in token: + printt_err(required_key, "not found in configuration file in configuration for to token", + token['SYMBOL']) + exit(-1) + + token_defaults = { + 'SLIPPAGE': 49, + 'MAXTOKENS': 0, + 'MOONBAG': 0, + 'SELLAMOUNTINTOKENS': 'all', + 'GAS': 20, + 'BOOSTPERCENT': 50, + 'GASLIMIT': 1000000 + + } + + for default_key in token_defaults: + if default_key not in token: + printt_v(default_key, "not found in configuration file in configuration for to token", token['SYMBOL'], + "setting a value of", token_defaults['default_key']) + token[default_key] = token_defaults[default_key] + elif default_key == 'SELLAMOUNTINTOKENS': + token_defaults[default_key] = token_defaults[default_key].lower() + + return tokens + + +""""""""""""""""""""""""""" +//PRELOAD +""""""""""""""""""""""""""" +print(timestamp(), "Preloading Data") +settings = load_settings_file(command_line_args.settings) + +directory = './abi/' +filename = "standard.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + standardAbi = json.load(json_file) + +directory = './abi/' +filename = "lp.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + lpAbi = json.load(json_file) + +directory = './abi/' +filename = "router.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + routerAbi = json.load(json_file) + +directory = './abi/' +filename = "factory2.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + factoryAbi = json.load(json_file) + +directory = './abi/' +filename = "koffee.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + koffeeAbi = json.load(json_file) + +directory = './abi/' +filename = "pangolin.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + pangolinAbi = json.load(json_file) + +directory = './abi/' +filename = "joeRouter.json" +file_path = os.path.join(directory, filename) +with open(file_path) as json_file: + joeRouter = json.load(json_file) + +""""""""""""""""""""""""""" +//ERROR LOGGING +""""""""""""""""""""""""""" +os.makedirs('./logs', exist_ok=True) + +if not os.path.exists('./logs/errors.log'): + open('./logs/errors.log', 'w').close() + +if not os.path.exists('./logs/exceptions.log'): + open('./logs/exceptions.log', 'w').close() + +log_format = '%(levelname)s: %(asctime)s %(message)s' +logging.basicConfig(filename='./logs/errors.log', + level=logging.INFO, + format=log_format) + +logger1 = logging.getLogger('1') +logger1.addHandler(logging.FileHandler('./logs/exceptions.log')) + +logging.info("*************************************************************************************") +logging.info("For Help & To Learn More About how the bot works please visit our wiki here:") +logging.info("https://cryptognome.gitbook.io/limitswap/") +logging.info("*************************************************************************************") + +""""""""""""""""""""""""""" +//NETWORKS SELECT +""""""""""""""""""""""""""" + +if settings['EXCHANGE'].lower() == 'pancakeswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + print(timestamp(), 'Using custom node.') + else: + my_provider = "https://bsc-dataseed4.defibit.io" + + if not my_provider: + print(timestamp(), 'Custom node empty. Exiting') + exit(1) + + if my_provider[0].lower() == 'h': + print(timestamp(), 'Using HTTPProvider') + client = Web3(Web3.HTTPProvider(my_provider)) + elif my_provider[0].lower() == 'w': + print(timestamp(), 'Using WebsocketProvider') + client = Web3(Web3.WebsocketProvider(my_provider)) + else: + print(timestamp(), 'Using IPCProvider') + client = Web3(Web3.IPCProvider(my_provider)) + + print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + + if settings['EXCHANGEVERSION'] == "1": + routerAddress = Web3.toChecksumAddress("0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F") + factoryAddress = Web3.toChecksumAddress("0xbcfccbde45ce874adcb698cc183debcf17952812") + elif settings['EXCHANGEVERSION'] == "2": + routerAddress = Web3.toChecksumAddress("0x10ED43C718714eb63d5aA57B78B54704E256024E") + factoryAddress = Web3.toChecksumAddress("0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73") + + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") + base_symbol = "BNB" + rugdocchain = '&chain=bsc' + modified = False + +if settings['EXCHANGE'].lower() == 'traderjoe': + + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://api.avax.network/ext/bc/C/rpc" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "AVAX Smart Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + + routerAddress = Web3.toChecksumAddress("0x60aE616a2155Ee3d9A68541Ba4544862310933d4") + factoryAddress = Web3.toChecksumAddress("0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10") + + routerContract = client.eth.contract(address=routerAddress, abi=joeRouter) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7") + base_symbol = "AVAX" + rugdocchain = '&chain=avax' + modified = True + +elif settings['EXCHANGE'].lower() == 'pinkswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + print(timestamp(), 'Using custom node.') + else: + my_provider = "https://bsc-dataseed4.defibit.io" + + if not my_provider: + print(timestamp(), 'Custom node empty. Exiting') + exit(1) + + if my_provider[0].lower() == 'h': + print(timestamp(), 'Using HTTPProvider') + client = Web3(Web3.HTTPProvider(my_provider)) + elif my_provider[0].lower() == 'w': + print(timestamp(), 'Using WebsocketProvider') + client = Web3(Web3.WebsocketProvider(my_provider)) + else: + print(timestamp(), 'Using IPCProvider') + client = Web3(Web3.IPCProvider(my_provider)) + + print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) + print(timestamp(), "Loading PinkSwap Smart Contracts...") + + routerAddress = Web3.toChecksumAddress("0x319EF69a98c8E8aAB36Aea561Daba0Bf3D0fa3ac") + factoryAddress = Web3.toChecksumAddress("0x7d2ce25c28334e40f37b2a068ec8d5a59f11ea54") + + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + + weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") + base_symbol = "BNB" + rugdocchain = '&chain=bsc' + modified = False + +elif settings['EXCHANGE'].lower() == 'biswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + print(timestamp(), 'Using custom node.') + else: + my_provider = "https://bsc-dataseed4.defibit.io" + + if not my_provider: + print(timestamp(), 'Custom node empty. Exiting') + exit(1) + + if my_provider[0].lower() == 'h': + print(timestamp(), 'Using HTTPProvider') + client = Web3(Web3.HTTPProvider(my_provider)) + elif my_provider[0].lower() == 'w': + print(timestamp(), 'Using WebsocketProvider') + client = Web3(Web3.WebsocketProvider(my_provider)) + else: + print(timestamp(), 'Using IPCProvider') + client = Web3(Web3.IPCProvider(my_provider)) + + print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) + print(timestamp(), "Loading PinkSwap Smart Contracts...") + + routerAddress = Web3.toChecksumAddress("0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8") + factoryAddress = Web3.toChecksumAddress("0x858E3312ed3A876947EA49d572A7C42DE08af7EE") + + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + + weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") + base_symbol = "BNB" + rugdocchain = '&chain=bsc' + modified = False + +elif settings['EXCHANGE'].lower() == 'apeswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://bsc-dataseed4.defibit.io" + + client = Web3(Web3.HTTPProvider(my_provider)) + + print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) + print(timestamp(), "Loading ApeSwap Smart Contracts...") + + routerAddress = Web3.toChecksumAddress("0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7") + factoryAddress = Web3.toChecksumAddress("0x0841BD0B734E4F5853f0dD8d7Ea041c241fb0Da6") + + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + + weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") + busd = Web3.toChecksumAddress("0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56") + base_symbol = "BNB" + rugdocchain = '&chain=bsc' + modified = False + +elif settings["EXCHANGE"].lower() == 'uniswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://pedantic-montalcini:lair-essay-ranger-rigid-hardy-petted@nd-857-678-344.p2pify.com" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "Uniswap Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D") + factoryAddress = Web3.toChecksumAddress("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + base_symbol = "ETH" + rugdocchain = '&chain=eth' + modified = False + +elif settings["EXCHANGE"].lower() == 'kuswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://rpc-mainnet.kcc.network" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "Kucoin Chain Connected =", client.isConnected()) + print(timestamp(), "Loading KuSwap Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0xa58350d6dee8441aa42754346860e3545cc83cda") + factoryAddress = Web3.toChecksumAddress("0xAE46cBBCDFBa3bE0F02F463Ec5486eBB4e2e65Ae") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x4446Fc4eb47f2f6586f9fAAb68B3498F86C07521") + base_symbol = "KCS" + rugdocchain = '&chain=kcc' + modified = False + +elif settings["EXCHANGE"].lower() == 'koffeeswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://rpc-mainnet.kcc.network" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "Kucoin Chain Connected =", client.isConnected()) + print(timestamp(), "Loading KoffeeSwap Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0xc0fFee0000C824D24E0F280f1e4D21152625742b") + factoryAddress = Web3.toChecksumAddress("0xC0fFeE00000e1439651C6aD025ea2A71ED7F3Eab") + routerContract = client.eth.contract(address=routerAddress, abi=koffeeAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x4446Fc4eb47f2f6586f9fAAb68B3498F86C07521") + base_symbol = "KCS" + rugdocchain = '&chain=kcc' + modified = True + +elif settings["EXCHANGE"].lower() == 'spookyswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://rpcapi.fantom.network" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "FANTOM Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0xF491e7B69E4244ad4002BC14e878a34207E38c29") + factoryAddress = Web3.toChecksumAddress("0x152eE697f2E276fA89E96742e9bB9aB1F2E61bE3") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83") + base_symbol = "FTM" + rugdocchain = '&chain=ftm' + modified = False + +elif settings["EXCHANGE"].lower() == 'spiritswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://rpcapi.fantom.network" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "FANTOM Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0x16327E3FbDaCA3bcF7E38F5Af2599D2DDc33aE52") + factoryAddress = Web3.toChecksumAddress("0xEF45d134b73241eDa7703fa787148D9C9F4950b0") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83") + base_symbol = "FTM" + rugdocchain = '&chain=ftm' + modified = False + +elif settings["EXCHANGE"].lower() == 'quickswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://polygon-rpc.com" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "Matic Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff") + factoryAddress = Web3.toChecksumAddress("0x5757371414417b8c6caad45baef941abc7d3ab32") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270") + base_symbol = "MATIC" + rugdocchain = '&chain=poly' + modified = False + +elif settings["EXCHANGE"].lower() == 'waultswap': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://rpc-waultfinance-mainnet.maticvigil.com/v1/0bc1bb1691429f1eeee66b2a4b919c279d83d6b0" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "Matic Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0x3a1D87f206D12415f5b0A33E786967680AAb4f6d") + factoryAddress = Web3.toChecksumAddress("0xa98ea6356A316b44Bf710D5f9b6b4eA0081409Ef") + routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270") + base_symbol = "MATIC" + rugdocchain = '&chain=poly' + modified = False + +elif settings["EXCHANGE"].lower() == 'pangolin': + if settings['USECUSTOMNODE'].lower() == 'true': + my_provider = settings['CUSTOMNODE'] + else: + my_provider = "https://api.avax.network/ext/bc/C/rpc" + + client = Web3(Web3.HTTPProvider(my_provider)) + print(timestamp(), "AVAX Chain Connected =", client.isConnected()) + print(timestamp(), "Loading Smart Contracts...") + routerAddress = Web3.toChecksumAddress("0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106") + factoryAddress = Web3.toChecksumAddress("0xefa94DE7a4656D787667C749f7E1223D71E9FD88") + routerContract = client.eth.contract(address=routerAddress, abi=pangolinAbi) + factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) + weth = Web3.toChecksumAddress("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7") + base_symbol = "AVAX" + rugdocchain = '&chain=avax' + modified = True + + +def get_password(): + # Function: get_password + # ---------------------------- + # Handles the decision making logic concerning private key encryption and asking the user for their password. + # + # returns: the user's password + + settings_changed = False + setnewpassword = False + + # Check to see if the user has a version of the settings file before private key encryption existed + if 'ENCRYPTPRIVATEKEYS' not in settings: + response = "" + settings_changed = True + while response != "y" and response != "n": + print("\nWould you like to use a password to encrypt your private keys?") + response = input("You will need to input this password each time LimitSwap is executed (y/n): ") + + if response == "y": + settings['ENCRYPTPRIVATEKEYS'] = "true" + setnewpassword = True + else: + settings['ENCRYPTPRIVATEKEYS'] = "false" + + # If the user wants to encrypt their private keys, but we don't have an encrypted private key recorded, we need to ask for a password + elif settings['ENCRYPTPRIVATEKEYS'] == "true" and not settings['PRIVATEKEY'].startswith('aes:'): + print("\nPlease create a password to encrypt your private keys.") + setnewpassword = True + + # Set a new password when necessary + if setnewpassword == True: + settings_changed = True + passwords_differ = True + while passwords_differ: + pwd = pwinput.pwinput(prompt="\nType your new password: ") + pwd2 = pwinput.pwinput(prompt="\nType your new password again: ") + + if pwd != pwd2: + print("Error, password mismatch. Try again.") + else: + passwords_differ = False + + # The user already has encrypted private keys. Accept a password so we can unencrypt them + elif settings['ENCRYPTPRIVATEKEYS'] == "true": + + if command_line_args.password: + pwd = command_line_args.password + else: + pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") + + else: + pwd = "" + + if not pwd.strip(): + print() + print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") + print("X You are running LimitSwap without encrypting your private keys. X") + print("X Private keys are stored on disk unencrypted and can be accessed by X") + print("X anyone with access to the file system, including the Systems/VPS administrator X") + print("X and anyone with physical access to the machine or hard drives. X") + print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") + print() + + if settings_changed == True: + save_settings(settings, pwd) + + return pwd + + +# RUGDOC CONTROL IMPLEMENTATION +# Honeypot API details +honeypot_url = 'https://honeypot.api.rugdoc.io/api/honeypotStatus.js?address=' + +# Rugdoc's answers interpretations +interpretations = { + "UNKNOWN": (style.RED + '\nThe status of this token is unknown. ' + 'This is usually a system error but could \n also be a bad sign for the token. Be careful.'), + "OK": (style.GREEN + '\nRUGDOC API RESULT : OK \n' + '√ Honeypot tests passed. RugDoc program was able to buy and sell it successfully. This however does not guarantee that it is not a honeypot.'), + "NO_PAIRS": (style.RED + '\nRUGDOC API RESULT : NO_PAIRS \n' + '⚠ Could not find any trading pair for this token on the default router and could thus not test it.'), + "SEVERE_FEE": (style.RED + '\nRUGDOC API RESULT : SEVERE_FEE \n' + '/!\ /!\ A severely high trading fee (over 50%) was detected when selling or buying this token.'), + "HIGH_FEE": (style.YELLOW + '\nRUGDOC API RESULT : HIGH_FEE \n' + '/!\ /!\ A high trading fee (Between 20% and 50%) was detected when selling or buying this token. Our system was however able to sell the token again.'), + "MEDIUM_FEE": (style.YELLOW + '\nRUGDOC API RESULT : MEDIUM_FEE \n' + '/!\ A trading fee of over 10% but less then 20% was detected when selling or buying this token. Our system was however able to sell the token again.'), + "APPROVE_FAILED": (style.RED + '\nRUGDOC API RESULT : APPROVE_FAILED \n' + '/!\ /!\ /!\ Failed to approve the token.\n This is very likely a honeypot.'), + "SWAP_FAILED": (style.RED + '\nRUGDOC API RESULT : SWAP_FAILED \n' + '/!\ /!\ /!\ Failed to sell the token. \n This is very likely a honeypot.'), + "chain not found": (style.RED + '\nRUGDOC API RESULT : chain not found \n' + '/!\ Sorry, rugdoc API does not work on this chain... (it does not work on ETH, mainly) \n') +} + + +# Function to check rugdoc API +def honeypot_check(address): + url = (honeypot_url + address + rugdocchain) + # sending get request and saving the response as response object + return requests.get(url) + + +def save_settings(settings, pwd): + if len(pwd) > 0: + encrypted_settings = settings.copy() + encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], + pwd) + encrypted_settings['PRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['PRIVATEKEY'], pwd) + + # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our + # settings.json output so that it's reasable. This should probably be fixed by us importing + # the entire json file, instead of just the [0] element. + + print(timestamp(), "Writing settings to file.") + + if settings['ENCRYPTPRIVATEKEYS'] == "true": + output_settings = encrypted_settings + else: + output_settings = settings + + with open(command_line_args.settings, 'w') as f: + f.write("[\n") + f.write(json.dumps(output_settings, indent=4)) + f.write("\n]\n") + + +def parse_wallet_settings(settings, pwd): + # Function: load_wallet_settings + # ---------------------------- + # Handles the process of deciding whether or not the user's private key needs to be decrypted + # Accepts user input for new private keys and wallet addresses + # + # returns: none (exits on incorrect password) + + settings_changed = False + + # Check for limit wallet information + if " " in settings['LIMITWALLETADDRESS'] or settings['LIMITWALLETADDRESS'] == "": + settings_changed = True + settings['LIMITWALLETADDRESS'] = input("Please provide the wallet address where you have your LIMIT: ") + + # Check for limit wallet private key + if " " in settings['LIMITWALLETPRIVATEKEY'] or settings['LIMITWALLETPRIVATEKEY'] == "": + settings_changed = True + settings['LIMITWALLETPRIVATEKEY'] = input( + "Please provide the private key for the wallet where you have your LIMIT: ") + + # If the limit wallet private key is already set and encrypted, decrypt it + elif settings['LIMITWALLETPRIVATEKEY'].startswith('aes:'): + printt("Decrypting limit wallet private key.") + settings['LIMITWALLETPRIVATEKEY'] = settings['LIMITWALLETPRIVATEKEY'].replace('aes:', "", 1) + settings['LIMITWALLETPRIVATEKEY'] = cryptocode.decrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) + + if settings['LIMITWALLETPRIVATEKEY'] == False: + print(style.RED + "ERROR: Your private key decryption password is incorrect") + print(style.RESET + "Please re-launch the bot and try again") + sleep(10) + sys.exit() + + # Check for trading wallet information + if " " in settings['WALLETADDRESS'] or settings['WALLETADDRESS'] == "": + settings_changed = True + settings['WALLETADDRESS'] = input("Please provide the wallet address for your trading wallet: ") + + # Check for trading wallet private key + if " " in settings['PRIVATEKEY'] or settings['PRIVATEKEY'] == "": + settings_changed = True + settings['PRIVATEKEY'] = input("Please provide the private key for the wallet you want to trade with: ") + + # If the trading wallet private key is already set and encrypted, decrypt it + elif settings['PRIVATEKEY'].startswith('aes:'): + print(timestamp(), "Decrypting limit wallet private key.") + settings['PRIVATEKEY'] = settings['PRIVATEKEY'].replace('aes:', "", 1) + settings['PRIVATEKEY'] = cryptocode.decrypt(settings['PRIVATEKEY'], pwd) + + if settings_changed == True: + save_settings(settings, pwd) + + +def decimals(address): + try: + balanceContract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) + decimals = balanceContract.functions.decimals().call() + DECIMALS = 10 ** decimals + except ABIFunctionNotFound: + DECIMALS = 10 ** 18 + except ValueError as ve: + logging.exception(ve) + print("Please check your SELLPRICE values.") + return DECIMALS + + +def check_logs(): + print(timestamp(), "Quickly Checking Log Size") + with open('./logs/errors.log') as f: + line_count = 0 + for line in f: + line_count += 1 + if line_count > 100: + with open('./logs/errors.log', "r") as f: + lines = f.readlines() + + with open('./logs/errors.log', "w") as f: + f.writelines(lines[20:]) + + f.close() + + +def decode_key(): + private_key = settings['LIMITWALLETPRIVATEKEY'] + acct = client.eth.account.privateKeyToAccount(private_key) + addr = acct.address + return addr + + +def check_release(): + try: + url = 'https://api.github.com/repos/CryptoGnome/LimitSwap/releases/latest' + r = requests.get(url).json()['tag_name'] + print("Checking Latest Release Version on Github, Please Make Sure You are Staying Updated = ", r) + logging.info("Checking Latest Release Version on Github, Please Make Sure You are Staying Updated = " + r) + except Exception: + r = "github api down, please ignore" + + return r + + +def auth(): + my_provider2 = 'https://reverent-raman:photo-hamlet-ankle-saved-scared-bobbed@nd-539-402-515.p2pify.com' + client2 = Web3(Web3.HTTPProvider(my_provider2)) + print(timestamp(), "Connected to Ethereum BlockChain =", client2.isConnected()) + # Insert LIMITSWAP Token Contract Here To Calculate Staked Verification + address = Web3.toChecksumAddress("0xab95e915c123fded5bdfb6325e35ef5515f1ea69") + abi = standardAbi + balanceContract = client2.eth.contract(address=address, abi=abi) + decimals = balanceContract.functions.decimals().call() + DECIMALS = 10 ** decimals + + # Exception for incorrect Key Input + try: + decode = decode_key() + except Exception: + print("There is a problem with your private key : please check if it's correct. Don't enter seed phrase !") + logging.info( + "There is a problem with your private key : please check if it's correct. Don't enter seed phrase !") + + wallet_address = Web3.toChecksumAddress(decode) + balance = balanceContract.functions.balanceOf(wallet_address).call() + true_balance = balance / DECIMALS + print(timestamp(), "Current Tokens Staked =", true_balance) + logging.info("Current Tokens Staked = " + str(true_balance)) + return true_balance + + +def approve(address, amount): + print(timestamp(), "Approving", address) + + eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') + + if eth_balance > 0.00005: + print("Estimating Gas Cost Using Web3") + if settings['EXCHANGE'].lower() == 'uniswap': + print("Estimating Gas Cost Using Web3") + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price =", gas) + + elif settings['EXCHANGE'].lower() == 'pancakeswap': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + elif settings['EXCHANGE'].lower() == 'spiritswap': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + elif settings['EXCHANGE'].lower() == 'spookyswap': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + elif settings['EXCHANGE'].lower() == 'pangolin': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + elif settings['EXCHANGE'].lower() == 'quickswap': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + elif settings['EXCHANGE'].lower() == 'kuswap' or 'koffeeswap': + gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) + print("Current Gas Price = ", gas) + else: + print("EXCHANGE NAME IN SETTINGS IS SPELLED INCORRECTLY OR NOT SUPPORTED YET CHECK WIKI!") + logging.info("EXCHANGE NAME IN SETTINGS IS SPELLED INCORRECTLY OR NOT SUPPORTED YET CHECK WIKI!") + exit() + + contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) + transaction = contract.functions.approve(routerAddress, amount).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': 300000, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) + + try: + return client.eth.sendRawTransaction(signed_txn.rawTransaction) + finally: + print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) + # LOG TX TO JSON + with open('./transactions.json', 'r') as fp: + data = json.load(fp) + tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) + tx_input = {"hash": tx_hash} + data.append(tx_input) + with open('./transactions.json', 'w') as fp: + json.dump(data, fp, indent=2) + fp.close() + + return tx_hash + else: + print(timestamp(), + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + logging.info( + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + sleep(10) + sys.exit() + + +def check_approval(address, balance): + print(timestamp(), "Checking Approval Status", address) + contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) + allowance = contract.functions.allowance(Web3.toChecksumAddress(settings['WALLETADDRESS']), routerAddress).call() + + if int(allowance) < int(balance): + + if settings["EXCHANGE"].lower() == 'quickswap': + print("Revert to Zero To change approval") + tx = approve(address, 0) + wait_for_tx(tx, address, False) + tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) + wait_for_tx(tx, address, False) + else: + print(style.YELLOW + "\n ---------------------------------------------------------------------------\n" + " You need to APPROVE this token before selling it : LimitSwap will do it now\n" + " ---------------------------------------------------------------------------\n") + print(style.RESET + "\n") + + tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) + wait_for_tx(tx, address, False) + print(style.GREEN + "\n ---------------------------------------------------------\n" + " Token is now approved : LimitSwap will make a BUY order\n" + " ---------------------------------------------------------\n") + print(style.RESET + "\n") + + return + + else: + pass + + +def check_bnb_balance(): + balance = client.eth.getBalance(settings['WALLETADDRESS']) + print(timestamp(), "Current Wallet Balance is :", Web3.fromWei(balance, 'ether'), base_symbol) + return balance + + +def check_balance(address, symbol): + address = Web3.toChecksumAddress(address) + DECIMALS = decimals(address) + balanceContract = client.eth.contract(address=address, abi=standardAbi) + balance = balanceContract.functions.balanceOf(settings['WALLETADDRESS']).call() + print(timestamp(), "Current Wallet Balance is: " + str(balance / DECIMALS) + " " + symbol) + + return balance + + +def fetch_pair(inToken, outToken): + print(timestamp(), "Fetching Pair Address") + pair = factoryContract.functions.getPair(inToken, outToken).call() + print(timestamp(), "Pair Address = ", pair) + return pair + + +def sync(inToken, outToken): + pair = factoryContract.functions.getPair(inToken, outToken).call() + syncContract = client.eth.contract(address=Web3.toChecksumAddress(pair), abi=lpAbi) + sync = syncContract.functions.sync().call() + + +def check_pool(inToken, outToken, symbol): + # This function is made to calculate Liquidity of a token + pair_address = factoryContract.functions.getPair(inToken, outToken).call() + DECIMALS = decimals(outToken) + pair_contract = client.eth.contract(address=pair_address, abi=lpAbi) + reserves = pair_contract.functions.getReserves().call() + pooled = reserves[1] / DECIMALS + # print("Debug LIQUIDITYAMOUNT line 627 :", pooled, "in token:", outToken) + + return pooled + + +def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase, sellpriceinbase): + # CHECK GET RATE OF THE TOKEn + + DECIMALS = decimals(inToken) + stamp = timestamp() + + if custom.lower() == 'false': + base = base_symbol + else: + pass + + if routing == 'true': + if outToken != weth: + price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth, outToken]).call()[-1] + DECIMALS = decimals(outToken) + tokenPrice = price_check / DECIMALS + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) + else: + price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] + DECIMALS = decimals(outToken) + tokenPrice = price_check / DECIMALS + price_output = "{:.18f}".format(tokenPrice) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) + + else: + if outToken != weth: + price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, outToken]).call()[-1] + DECIMALS = decimals(outToken) + tokenPrice = price_check / DECIMALS + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) + else: + price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] + DECIMALS = decimals(outToken) + tokenPrice = price_check / DECIMALS + price_output = "{:.18f}".format(tokenPrice) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) + + return tokenPrice + + +def wait_for_tx(tx_hash, address, check): + print(timestamp(), "............Waiting 1 minute for TX to Confirm............") + timeout = time() + 60 + while True: + print(timestamp(), "............Waiting 1 minute for TX to Confirm............") + sleep(1) + try: + txn_receipt = client.eth.getTransactionReceipt(tx_hash) + return txn_receipt['status'] + + except Exception as e: + txn_receipt = None + + if txn_receipt is not None and txn_receipt['blockHash'] is not None: + return txn_receipt['status'] + + elif time() > timeout: + print(style.RED + "\n") + print(timestamp(), "Transaction was not confirmed after 1 minute : something wrong happened.\n" + "Please check if :\n" + "- your node is running correctly\n" + "- you have enough Gaslimit (check 'Gas Used by Transaction') if you have a failed Tx") + print(style.RESET + "\n") + failedtransactionsamount += 1 + logging.info("Transaction was not confirmed after 1 minute, breaking Check Cycle....") + sleep(5) + break + + # loop to check for balance after purchase + if check == True: + timeout = time() + 30 + print(style.RESET + "\n") + + while True: + print(timestamp(), ".........Waiting 30s to check tokens balance in your wallet after purchase............") + sleep(1) + + balance = check_balance(address, address) + + if balance > 0: + break + elif time() > timeout: + print(timestamp(), + "NO BUY FOUND, WE WILL CHECK A FEW TIMES TO SEE IF THERE IS BLOCKCHAIN DELAY, IF NOT WE WILL ASSUME THE TX HAS FAILED") + logging.info( + "NO BUY FOUND, WE WILL CHECK A FEW TIMES TO SEE IF THERE IS BLOCKCHAIN DELAY, IF NOT WE WILL ASSUME THE TX HAS FAILED") + break + + +def preapprove(tokens): + for token in tokens: + check_approval(token['ADDRESS'], 115792089237316195423570985008687907853269984665640564039457584007913129639934) + + if token['USECUSTOMBASEPAIR'].lower() == 'false': + check_approval(weth, 115792089237316195423570985008687907853269984665640564039457584007913129639934) + else: + check_approval(token['BASEADDRESS'], + 115792089237316195423570985008687907853269984665640564039457584007913129639934) + + +def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, + failedtransactionsnumber): + seconds = int(waitseconds) + if int(failedtransactionsamount) == int(failedtransactionsnumber): + print( + style.RED + "\n ---------------------------------------------------------------\n" + " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" + " ---------------------------------------------------------------\n\n") + + logging.info("Bot has reached maximum FAILED TRANSACTIONS number: it stops") + sleep(10) + sys.exit() + else: + + if waitseconds != '0': + print("Bot will wait", waitseconds, " seconds before buy, as you entered in BUYAFTER_XXX_SECONDS parameter") + sleep(seconds) + + print(timestamp(), "Placing New Buy Order for " + symbol) + + if int(gaslimit) < 250000: + print( + "Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") + gaslimit = 300000 + + if custom.lower() == 'false': + balance = Web3.fromWei(check_bnb_balance(), 'ether') + base = base_symbol + else: + address = Web3.toChecksumAddress(inToken) + DECIMALS = decimals(address) + balance_check = check_balance(inToken, base) + balance = balance_check / DECIMALS + + if balance > Decimal(amount): + if gas.lower() == 'boost': + gas_check = client.eth.gasPrice + gas_price = gas_check / 1000000000 + gas = (gas_price * ((int(boost)) / 100)) + gas_price + else: + gas = int(gas) + + gaslimit = int(gaslimit) + slippage = int(slippage) + DECIMALS = decimals(inToken) + amount = int(float(amount) * DECIMALS) + + if custom.lower() == 'false': + # if USECUSTOMBASEPAIR = false + amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + + deadline = int(time() + + 60) + + # THIS SECTION IS FOR MODIFIED CONTRACTS : EACH EXCHANGE NEEDS TO BE SPECIFIED + # USECUSTOMBASEPAIR = false + if modified == True: + + if settings["EXCHANGE"].lower() == 'koffeeswap': + transaction = routerContract.functions.swapExactKCSForTokens( + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'value': amount, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': + transaction = routerContract.functions.swapExactAVAXForTokens( + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'value': amount, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + + else: + # USECUSTOMBASEPAIR = false + # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. + + # Special condition on Uniswap, to implement EIP-1559 + if settings["EXCHANGE"].lower() == 'uniswap': + transaction = routerContract.functions.swapExactETHForTokens( + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # USECUSTOMBASEPAIR = false + # for all the rest of exchanges with Modified = false + transaction = routerContract.functions.swapExactETHForTokens( + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'value': amount, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # USECUSTOMBASEPAIR = true + if inToken == weth: + # USECUSTOMBASEPAIR = true + # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address + amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # LIQUIDITYINNATIVETOKEN = true + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + if routing.lower() == 'true': + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[ + -1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if settings["EXCHANGE"].lower() == 'uniswap': + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # LIQUIDITYINNATIVETOKEN = true + + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # LIQUIDITYINNATIVETOKEN = true + # Exchange different from Uniswap + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] + if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': + min_tokens = 100 + else: + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if settings["EXCHANGE"].lower() == 'uniswap': + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # Special condition on Uniswap, to implement EIP-1559 + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # Base Pair different from weth + # Exchange different from Uniswap + + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + sync(inToken, outToken) + signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) + + try: + return client.eth.sendRawTransaction(signed_txn.rawTransaction) + finally: + print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) + # LOG TX TO JSON + with open('./transactions.json', 'r') as fp: + data = json.load(fp) + tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) + tx_input = {"hash": tx_hash} + data.append(tx_input) + with open('./transactions.json', 'w') as fp: + json.dump(data, fp, indent=2) + fp.close() + + return tx_hash + + else: + print(timestamp(), "Not Enough " + base + " Balance to make buys") + logging.info("Not Enough " + base + " Balance to make buys") + return False + + +def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, routing): + print(timestamp(), "Placing Sell Order " + symbol) + balance = Web3.fromWei(check_balance(inToken, symbol), 'ether') + check_approval(inToken, balance * 1000000000) + + if int(gaslimit) < 250000: + gaslimit = 300000 + + if type(amount) == str: + amount_check = balance + else: + amount_check = Decimal(amount) + + if balance >= Decimal(amount_check) and balance > 0.0000000000000001: + + if gas.lower() == 'boost': + gas_check = client.eth.gasPrice + gas_price = gas_check / 1000000000 + gas = (gas_price * ((int(boost) * 4) / 100)) + gas_price + else: + gas = int(gas) + + slippage = int(slippage) + gaslimit = int(gaslimit) + DECIMALS = decimals(inToken) + + if amount.lower() == 'all': + balance = check_balance(inToken, symbol) + moonbag = int(Decimal(moonbag) * DECIMALS) + amount = int(Decimal(balance - moonbag)) + + else: + balance = check_balance(inToken, symbol) + amount = Decimal(amount) * DECIMALS + moonbag = int(Decimal(moonbag) * DECIMALS) + + if balance < amount: + print(timestamp(), "Selling Remaining ", symbol) + amount = int(Decimal(balance - moonbag)) + else: + amount = int(Decimal(balance - moonbag)) + if amount > 0: + print(timestamp(), "Selling", amount / DECIMALS, symbol) + else: + print("Not enough left to sell, would bust moonbag") + amount = 0 + + if custom.lower() == 'false': + # USECUSTOMBASEPAIR = false + sync(inToken, weth) + + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if fees.lower() == 'true': + + # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED + if modified == True: + # USECUSTOMBASEPAIR = false + # HASFEES = true + + if settings["EXCHANGE"].lower() == 'koffeeswap': + transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + if settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': + transaction = routerContract.functions.swapExactTokensForAVAXSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. + # USECUSTOMBASEPAIR = false + # HASFEES = true + transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + else: + # USECUSTOMBASEPAIR = false + # HASFEES = false + + # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED + if modified == True: + # USECUSTOMBASEPAIR = false + # HASFEES = false + # Modified = true + + if settings["EXCHANGE"].lower() == 'koffeeswap': + transaction = routerContract.functions.swapExactTokensForKCS( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': + transaction = routerContract.functions.swapExactTokensForAVAX( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # USECUSTOMBASEPAIR = false + # HASFEES = false + # Modified = false --> uniswap / pancakeswap / apeswap, etc. + + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForETH( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # for all the rest of exchanges with Modified = false + transaction = routerContract.functions.swapExactTokensForETH( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # USECUSTOMBASEPAIR = true + if outToken == weth: + # if user has set WETH or WBNB as Custom base pair + sync(inToken, outToken) + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if fees.lower() == 'true': + # USECUSTOMBASEPAIR = true + # HASFEES = true + + if int(gaslimit) < 950000: + gaslimit = 950000 + + # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED + if modified == True: + # USECUSTOMBASEPAIR = true + # HASFEES = true + # Modified = true + + if settings["EXCHANGE"].lower() == 'koffeeswap': + transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': + transaction = routerContract.functions.swapExactTokensForAVAXSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # USECUSTOMBASEPAIR = true + # HASFEES = true + # Modified = false + + transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + else: + # USECUSTOMBASEPAIR = true + # HASFEES = false + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + + else: + sync(inToken, outToken) + + if routing.lower() == 'false' and outToken != weth: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if fees.lower() == 'true': + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # HASFEES = true + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # for all the rest of exchanges + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # HASFEES = false + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + # for all the rest of exchanges + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + elif routing.lower() == 'false' and outToken == weth: + # LIQUIDITYINNATIVETOKEN = false + # USECUSTOMBASEPAIR = true + # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address + print( + "ERROR IN YOUR TOKENS.JSON : YOU NEED TO CHOOSE THE PROPER BASE PAIR AS SYMBOL IF YOU ARE TRADING OUTSIDE OF NATIVE LIQUIDITY POOL") + + else: + amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[-1] + min_tokens = int(amount_out * (1 - (slippage / 100))) + deadline = int(time() + + 60) + + if fees.lower() == 'true': + # HASFEES = true + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + + else: + transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + else: + # HASFEES = false + if settings["EXCHANGE"].lower() == 'uniswap': + # Special condition on Uniswap, to implement EIP-1559 + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'maxFeePerGas': Web3.toWei(gas, 'gwei'), + 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), + 'type': "0x02" + }) + else: + transaction = routerContract.functions.swapExactTokensForTokens( + amount, + min_tokens, + [inToken, weth, outToken], + Web3.toChecksumAddress(settings['WALLETADDRESS']), + deadline + ).buildTransaction({ + 'gasPrice': Web3.toWei(gas, 'gwei'), + 'gas': gaslimit, + 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), + 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) + }) + + sync(inToken, outToken) + signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) + + try: + return client.eth.sendRawTransaction(signed_txn.rawTransaction) + finally: + print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) + # LOG TX TO JSON + with open('./transactions.json', 'r') as fp: + data = json.load(fp) + tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) + tx_input = {"hash": tx_hash} + data.append(tx_input) + with open('./transactions.json', 'w') as fp: + json.dump(data, fp, indent=2) + fp.close() + + return tx_hash + else: + pass + + +def run(): + global failedtransactionsamount + + try: + + tokens = load_tokens_file(command_line_args.tokens, True) + + eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') + + if eth_balance > 0.000005: + pass + else: + print( + style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") + logging.info( + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + sleep(10) + sys.exit() + + if settings['PREAPPROVE'].lower() == 'true': + preapprove(tokens) + else: + pass + + for token in tokens: + # Initialization of values, in case the user re-used some old tokens.json files + if 'RUGDOC_CHECK' not in token: + token['RUGDOC_CHECK'] = 'false' + if 'BUYAFTER_XXX_SECONDS' not in token: + token['BUYAFTER_XXX_SECONDS'] = 0 + if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 + # End of initialization of values + + if token['RUGDOC_CHECK'].lower() == 'true': + + honeypot = honeypot_check(address=token['ADDRESS']) + d = json.loads(honeypot.content) + for key, value in interpretations.items(): + if d["status"] in key: + honeypot_status = value + honeypot_code = key + print(honeypot_status) + + decision = "" + while decision != "y" and decision != "n": + print(style.RESET + "\nWhat is your decision?") + decision = input("Would you like to snipe this token? (y/n): ") + + if decision == "y": + print(style.RESET + "\nOK let's go!!\n") + pass + else: + sys.exit() + + else: + pass + + while True: + tokens = load_tokens_file(command_line_args.tokens, False) + + for token in tokens: + # Initialization of values, in case the user re-used some old tokens.json files + if 'RUGDOC_CHECK' not in token: + token['RUGDOC_CHECK'] = 'false' + if 'BUYAFTER_XXX_SECONDS' not in token: + token['BUYAFTER_XXX_SECONDS'] = 0 + if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 + # End of initialization of values + + if token['ENABLED'].lower() == 'true': + inToken = Web3.toChecksumAddress(token['ADDRESS']) + + if token['USECUSTOMBASEPAIR'].lower() == 'true': + outToken = Web3.toChecksumAddress(token['BASEADDRESS']) + else: + outToken = weth + + try: + quote = check_price(inToken, outToken, token['SYMBOL'], token['BASESYMBOL'], + token['USECUSTOMBASEPAIR'], token['LIQUIDITYINNATIVETOKEN'], + token['BUYPRICEINBASE'], token['SELLPRICEINBASE']) + pool = check_pool(inToken, outToken, token['BASESYMBOL']) + # print("Debug Liquidity Reserves ligne 1267:", float(pool)) + # print("Debug inToken : ", inToken, "outToken :", outToken) + + except Exception: + print(timestamp(), token['SYMBOL'], + " Not Listed For Trade Yet... waiting for liquidity to be added on exchange") + quote = 0 + + if quote < Decimal(token['BUYPRICEINBASE']) and quote != 0: + balance = check_balance(inToken, token['SYMBOL']) + DECIMALS = decimals(inToken) + if Decimal(balance / DECIMALS) < Decimal(token['MAXTOKENS']): + + if token["LIQUIDITYCHECK"].lower() == 'true': + pool = check_pool(inToken, outToken, token['BASESYMBOL']) + print(timestamp(), "You have set LIQUIDITYCHECK = true.") + print(timestamp(), "Current", token['SYMBOL'], "Liquidity = ", int(pool), "in token:", + outToken) + + if float(token['LIQUIDITYAMOUNT']) <= float(pool): + print(timestamp(), "LIQUIDITYAMOUNT parameter =", int(token['LIQUIDITYAMOUNT']), + " --> Enough liquidity detected : Buy Signal Found!") + log_price = "{:.18f}".format(quote) + logging.info("BuySignal Found @" + str(log_price)) + tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], + token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], + token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], + token['BASESYMBOL'], token['LIQUIDITYINNATIVETOKEN'], + token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + + if tx != False: + tx = wait_for_tx(tx, token['ADDRESS'], True) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + print(style.RESET + "") + sleep(3) + check_balance(token['ADDRESS'], token['SYMBOL']) + print(style.RESET + "\n") + sleep(3) + + if tx != 1: + # transaction is a FAILURE + print( + style.RED + "\n -------------------------------------------------\n" + " FAILURE ! Plese check your wallet. \n" + " Cause of failure can be : \n" + " - GASLIMIT too low\n" + " - SLIPPAGE too low\n" + " -------------------------------------------------\n\n") + print(style.RESET + "") + failedtransactionsamount += 1 + preapprove(tokens) + else: + # transaction is a SUCCESS + print( + style.GREEN + "\n ----------------------------------\n" + " SUCCESS : your Tx is confirmed :)\n" + " ----------------------------------\n") + print(style.RESET + "") + pass + + else: + # print("debug 1450") + pass + else: + print(timestamp(), "LIQUIDITYAMOUNT parameter =", int(token['LIQUIDITYAMOUNT']), + " : not enough liquidity, bot will not buy") + + else: + print(timestamp(), "Buy Signal Found!") + log_price = "{:.18f}".format(quote) + logging.info("BuySignal Found @" + str(log_price)) + tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], token['SLIPPAGE'], + token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], + token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['BASESYMBOL'], + token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + + if tx != False: + tx = wait_for_tx(tx, token['ADDRESS'], True) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + print(style.RESET + "") + sleep(3) + check_balance(token['ADDRESS'], token['SYMBOL']) + print(style.RESET + "\n") + sleep(3) + + if tx != 1: + # transaction is a FAILURE + print( + style.RED + "\n -------------------------------------------------\n" + " FAILURE ! Please check your wallet. \n" + " Cause of failure can be : \n" + " - GASLIMIT too low\n" + " - SLIPPAGE too low\n" + " -------------------------------------------------\n\n") + print(style.RESET + "") + failedtransactionsamount += 1 + preapprove(tokens) + else: + # transaction is a SUCCESS + print( + style.GREEN + "\n ----------------------------------\n" + " SUCCESS : your Tx is confirmed :)\n" + " ----------------------------------\n") + print(style.RESET + "") + pass + else: + # print("debug 1497") + pass + + + else: + print(timestamp(), "You own more tokens than your MAXTOKENS parameter for ", + token['SYMBOL']) + + if quote > Decimal(token['SELLPRICEINBASE']): + DECIMALS = decimals(inToken) + balance = check_balance(inToken, token['SYMBOL']) + moonbag = int(Decimal(token['MOONBAG']) * DECIMALS) + balance = int(Decimal(balance - moonbag)) + + if balance > 0: + print(timestamp(), "Sell Signal Found " + token['SYMBOL']) + log_price = "{:.18f}".format(quote) + logging.info("Sell Signal Found @" + str(log_price)) + tx = sell(token['SELLAMOUNTINTOKENS'], token['MOONBAG'], inToken, outToken, + token['GAS'], token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], + token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], + token['LIQUIDITYINNATIVETOKEN']) + wait_for_tx(tx, token['ADDRESS'], False) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + sleep(5) + print(style.RESET + "") + else: + pass + + + elif quote > Decimal(token['SELLPRICEINBASE']) and quote != 0: + DECIMALS = decimals(inToken) + balance = check_balance(inToken, token['SYMBOL']) + moonbag = int(Decimal(token['MOONBAG']) * DECIMALS) + balance = int(Decimal(balance - moonbag)) + + if balance > 0: + print(timestamp(), "Sell Signal Found " + token['SYMBOL']) + log_price = "{:.18f}".format(quote) + logging.info("Sell Signal Found @" + str(log_price)) + tx = sell(token['SELLAMOUNTINTOKENS'], token['MOONBAG'], inToken, outToken, token['GAS'], + token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], + token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['LIQUIDITYINNATIVETOKEN']) + wait_for_tx(tx, token['ADDRESS'], False) + print( + style.RESET + "\n --------------------------------------\n" + " √ Tx done. Check your wallet \n" + " --------------------------------------") + sleep(5) + print(style.RESET + "") + + else: + # Double Check For Buy if Sell Signal Triggers + if quote < Decimal(token['BUYPRICEINBASE']): + balance = check_balance(inToken, token['SYMBOL']) + if Web3.fromWei(balance, 'ether') < Decimal(token['MAXTOKENS']): + print(timestamp(), "Buy Signal Found!") + log_price = "{:.18f}".format(quote) + logging.info("Sell Signal Found @" + str(log_price)) + tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], + token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], + token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], + token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], + token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) + wait_for_tx(tx, token['ADDRESS'], False) + else: + print(timestamp(), "Bot has reached MAXTOKENS Position Size for ", token['SYMBOL']) + pass + else: + pass + + sleep(cooldown) + + except Exception as ee: + print(timestamp(), "ERROR. Please go to /log folder and open your error logs : you will find more details.") + logging.exception(ee) + logger1.exception(ee) + sleep(10) + print("Restarting LimitSwap") + logging.info("Restarting LimitSwap") + # Cooldown Logic + timeout = 10 + nonce = 0 + while True: + print(".........Restart Cooldown left " + str(timeout - nonce) + " seconds.............") + nonce += 1 + sleep(1) + if nonce > timeout: + run() + + +try: + + check_logs() + + # Get the user password on first run + userpassword = get_password() + + # Handle any proccessing that is necessary to load the private key for the wallet + parse_wallet_settings(settings, userpassword) + + # The LIMIT balance of the user. + true_balance = auth() + + version = 3.36 + logging.info("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) + print("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) + check_release() + + if true_balance >= 50: + print(timestamp(), "Professional Subscriptions Active") + cooldown = 0.01 + run() + + elif true_balance >= 25 and true_balance < 50: + print(timestamp(), "Trader Subscriptions Active") + cooldown = 3 + run() + elif true_balance >= 10 and true_balance < 25: + print(timestamp(), "Casual Subscriptions Active") + cooldown = 6 + run() + else: + print(timestamp(), + "10 - 50 $LIMIT tokens needed to use this bot, please visit the LimitSwap.com for more info or buy more tokens on Uniswap to use!") + logging.exception( + "10 - 50 $LIMIT tokens needed to use this bot, please visit the LimitSwap.com for more info or buy more tokens on Uniswap to use!") + + +except Exception as e: + print(timestamp(), "ERROR. Please go to /log folder and open your error logs : you will find more details.") + logging.exception(e) + logger1.exception(e) + print("Restarting LimitSwap") + logging.info("Restarting LimitSwap") + # Cooldown Logic + timeout = 10 + nonce = 0 + while True: + print(".........Restart Cooldown left " + str(timeout - nonce) + " seconds.............") + nonce += 1 + sleep(1) + if nonce > timeout: + run() + +# -*- coding: utf-8 -*- +from web3 import Web3 +from time import sleep, time +import json +from decimal import Decimal +import os +from web3.exceptions import ABIFunctionNotFound, TransactionNotFound, BadFunctionCallOutput +import logging +from datetime import datetime +import sys +import requests +import cryptocode, re, pwinput +import argparse +import signal + +# DEVELOPER CONSIDERATIONS +# +# USER INTERACTION - Do not depend on user interaction. If you develop a setting that is going to require +# user interaction while the bot is running, warn the user before hand. Accept a value before the check +# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's +# entire process from buying all the way to selling multiple positions and multiple pairs with zero user +# interaction. +# +# HANDLING NEW ENTRIES IN settings.json - When adding a new configuration item in settings.json be sure to +# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file. +# Do not assume a user has changed their settings.json file to work with the new version, your additions +# should be backwards compatible and have safe default values if possible +# +# HANDLING NEW ENTRIES IN tokens.json - When adding a new configuration item in tokens.json be sure to +# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file +# Do not assume a user has changed their tokens.json file to work with the new version, your additions +# should be backwards compatible and have safe default values if possible + + +# initialization of number of failed transactions +failedtransactionsamount = 0 + + +# color styles +class style(): # Class of different text colours - default is white + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + + # Function to cleanly exit on SIGINT def signal_handler(sig, frame): sys.exit(0) + + signal.signal(signal.SIGINT, signal_handler) + def timestamp(): timestamp = time() dt_object = datetime.fromtimestamp(timestamp) return dt_object + # # COMMAND LINE ARGUMENTS # parser = argparse.ArgumentParser() -parser.add_argument("-p", "--password", type=str, help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") -parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", default="./settings.json") -parser.add_argument("-t", "--tokens" , type=str, help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") -parser.add_argument("-v", "--verbose" , action='store_true', help="Print detailed messages to stdout") +parser.add_argument("-p", "--password", type=str, + help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") +parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", + default="./settings.json") +parser.add_argument("-t", "--tokens", type=str, + help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") +parser.add_argument("-v", "--verbose", action='store_true', help="Print detailed messages to stdout") command_line_args = parser.parse_args() + def printt(*print_args): # Function: printt # ---------------------------- @@ -77,7 +2259,8 @@ def printt(*print_args): # # returns: nothing - print(timestamp(),' '.join(map(str,print_args))) + print(timestamp(), ' '.join(map(str, print_args))) + def printt_v(*print_args): # Function: printt @@ -87,7 +2270,8 @@ def printt_v(*print_args): # returns: nothing if command_line_args.verbose == True: - print(timestamp(),' '.join(map(str,print_args))) + print(timestamp(), ' '.join(map(str, print_args))) + def printt_err(*print_args): # Function: printt_err @@ -96,9 +2280,10 @@ def printt_err(*print_args): # # returns: nothing - print(timestamp(), " ", style.RED, ' '.join(map(str,print_args)), style.RESET, sep="") + print(timestamp(), " ", style.RED, ' '.join(map(str, print_args)), style.RESET, sep="") + -def load_settings_file(settings_path, load_message = True): +def load_settings_file(settings_path, load_message=True): # Function: load_settings_file # ---------------------------- # loads the settings file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file @@ -116,15 +2301,15 @@ def load_settings_file(settings_path, load_message = True): f.close() for default_false in ['UNLIMITEDSLIPPAGE', 'USECUSTOMNODE']: - if default_false not in settings: - printt_v (default_false, "not found in settings configuration file, settings a default value of false.") + if default_false not in settings: + printt_v(default_false, "not found in settings configuration file, settings a default value of false.") settings[default_false] = "false" else: settings[default_false] = settings[default_false].lower() for default_true in ['PREAPPROVE']: if default_true not in settings: - printt_v (default_true, "not found in settings configuration file, settings a default value of true.") + printt_v(default_true, "not found in settings configuration file, settings a default value of true.") settings[default_true] = "true" else: settings[default_true] = settings[default_true].lower() @@ -132,14 +2317,15 @@ def load_settings_file(settings_path, load_message = True): # Keys that must be set for required_key in ['EXCHANGE']: if required_key not in settings: - printt_err (required_key, "not found in settings configuration file.") - exit (-1) + printt_err(required_key, "not found in settings configuration file.") + exit(-1) else: settings[required_key] = settings[required_key].lower() return settings -def load_tokens_file(tokens_path, load_message = True): + +def load_tokens_file(tokens_path, load_message=True): # Function: load_tokens_File # ---------------------------- # loads the token definition file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file @@ -161,32 +2347,34 @@ def load_tokens_file(tokens_path, load_message = True): for default_false in ['ENABLED', 'LIQUIDITYCHECK', 'LIQUIDITYINNATIVETOKEN', 'USECUSTOMBASEPAIR', 'HASFEES']: if default_false not in token: - printt_v (default_false, "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a default value of false") + printt_v(default_false, "not found in configuration file in configuration for to token", + token['SYMBOL'], "setting a default value of false") token[default_false] = "false" else: token[default_false] = token[default_false].lower() - # Keys that must be set - for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE' ]: + for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE']: if required_key not in token: - printt_err (required_key, "not found in configuration file in configuration for to token", token['SYMBOL']) - exit (-1) + printt_err(required_key, "not found in configuration file in configuration for to token", + token['SYMBOL']) + exit(-1) token_defaults = { - 'SLIPPAGE' : 49, - 'MAXTOKENS' : 0, - 'MOONBAG' : 0, - 'SELLAMOUNTINTOKENS' : 'all', - 'GAS' : 20, - 'BOOSTPERCENT' : 50, - 'GASLIMIT' : 1000000 + 'SLIPPAGE': 49, + 'MAXTOKENS': 0, + 'MOONBAG': 0, + 'SELLAMOUNTINTOKENS': 'all', + 'GAS': 20, + 'BOOSTPERCENT': 50, + 'GASLIMIT': 1000000 } for default_key in token_defaults: if default_key not in token: - printt_v (default_key , "not found in configuration file in configuration for to token", token['SYMBOL'], "setting a value of", token_defaults['default_key']) + printt_v(default_key, "not found in configuration file in configuration for to token", token['SYMBOL'], + "setting a value of", token_defaults['default_key']) token[default_key] = token_defaults[default_key] elif default_key == 'SELLAMOUNTINTOKENS': token_defaults[default_key] = token_defaults[default_key].lower() @@ -629,7 +2817,7 @@ def get_password(): print("X and anyone with physical access to the machine or hard drives. X") print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") print() - + if settings_changed == True: save_settings(settings, pwd) @@ -659,7 +2847,7 @@ def get_password(): "SWAP_FAILED": (style.RED + '\nRUGDOC API RESULT : SWAP_FAILED \n' '/!\ /!\ /!\ Failed to sell the token. \n This is very likely a honeypot.'), "chain not found": (style.RED + '\nRUGDOC API RESULT : chain not found \n' - '/!\ Sorry, rugdoc API does not work on this chain... (it does not work on ETH, mainly) \n') + '/!\ Sorry, rugdoc API does not work on this chain... (it does not work on ETH, mainly) \n') } @@ -671,7 +2859,6 @@ def honeypot_check(address): def save_settings(settings, pwd): - if len(pwd) > 0: encrypted_settings = settings.copy() encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], @@ -681,7 +2868,7 @@ def save_settings(settings, pwd): # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our # settings.json output so that it's reasable. This should probably be fixed by us importing # the entire json file, instead of just the [0] element. - + print(timestamp(), "Writing settings to file.") if settings['ENCRYPTPRIVATEKEYS'] == "true": @@ -704,7 +2891,7 @@ def parse_wallet_settings(settings, pwd): # returns: none (exits on incorrect password) settings_changed = False - + # Check for limit wallet information if " " in settings['LIMITWALLETADDRESS'] or settings['LIMITWALLETADDRESS'] == "": settings_changed = True @@ -971,26 +3158,30 @@ def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth, outToken]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) else: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) else: if outToken != weth: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, outToken]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) + print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) else: price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] DECIMALS = decimals(outToken) tokenPrice = price_check / DECIMALS price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, "//// your sellprice =", sellpriceinbase, base) + print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, + "//// your sellprice =", sellpriceinbase, base) return tokenPrice @@ -1055,10 +3246,12 @@ def preapprove(tokens): 115792089237316195423570985008687907853269984665640564039457584007913129639934) -def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, failedtransactionsnumber): +def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, + failedtransactionsnumber): seconds = int(waitseconds) if int(failedtransactionsamount) == int(failedtransactionsnumber): - print(style.RED + "\n ---------------------------------------------------------------\n" + print( + style.RED + "\n ---------------------------------------------------------------\n" " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" " ---------------------------------------------------------------\n\n") @@ -1074,7 +3267,8 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, print(timestamp(), "Placing New Buy Order for " + symbol) if int(gaslimit) < 250000: - print("Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") + print( + "Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") gaslimit = 300000 if custom.lower() == 'false': @@ -1100,7 +3294,7 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, amount = int(float(amount) * DECIMALS) if custom.lower() == 'false': - # if USECUSTOMBASEPAIR = false + # if USECUSTOMBASEPAIR = false amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': min_tokens = 100 @@ -1354,7 +3548,7 @@ def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, routing): print(timestamp(), "Placing Sell Order " + symbol) balance = Web3.fromWei(check_balance(inToken, symbol), 'ether') - check_approval(inToken, balance*1000000000) + check_approval(inToken, balance * 1000000000) if int(gaslimit) < 250000: gaslimit = 300000 @@ -1630,7 +3824,7 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee # USECUSTOMBASEPAIR = true # HASFEES = true if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 + # Special condition on Uniswap, to implement EIP-1559 transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( amount, min_tokens, @@ -1666,7 +3860,7 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee # USECUSTOMBASEPAIR = true # HASFEES = false if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 + # Special condition on Uniswap, to implement EIP-1559 transaction = routerContract.functions.swapExactTokensForTokens( amount, min_tokens, @@ -1712,7 +3906,7 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee if fees.lower() == 'true': # HASFEES = true if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 + # Special condition on Uniswap, to implement EIP-1559 transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( amount, min_tokens, @@ -1745,7 +3939,7 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee else: # HASFEES = false if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 + # Special condition on Uniswap, to implement EIP-1559 transaction = routerContract.functions.swapExactTokensForTokens( amount, min_tokens, @@ -1797,11 +3991,10 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee def run(): - global failedtransactionsamount try: - + tokens = load_tokens_file(command_line_args.tokens, True) eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') @@ -1809,8 +4002,10 @@ def run(): if eth_balance > 0.05: pass else: - print(style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") - logging.info("You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") + print( + style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") + logging.info( + "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") sleep(10) sys.exit() @@ -1828,7 +4023,7 @@ def run(): if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 # End of initialization of values - + if token['RUGDOC_CHECK'].lower() == 'true': honeypot = honeypot_check(address=token['ADDRESS']) @@ -1855,7 +4050,7 @@ def run(): while True: tokens = load_tokens_file(command_line_args.tokens, False) - + for token in tokens: # Initialization of values, in case the user re-used some old tokens.json files if 'RUGDOC_CHECK' not in token: @@ -1865,7 +4060,7 @@ def run(): if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 # End of initialization of values - + if token['ENABLED'].lower() == 'true': inToken = Web3.toChecksumAddress(token['ADDRESS']) @@ -1997,7 +4192,8 @@ def run(): else: - print(timestamp(), "You own more tokens than your MAXTOKENS parameter for ", token['SYMBOL']) + print(timestamp(), "You own more tokens than your MAXTOKENS parameter for ", + token['SYMBOL']) if quote > Decimal(token['SELLPRICEINBASE']): DECIMALS = decimals(inToken) @@ -2139,5 +4335,3 @@ def run(): if nonce > timeout: run() - - From 50df28ed25d2f10ed7547b19ecc94169e87436f9 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:13:13 +0100 Subject: [PATCH 07/16] Update LimitSwap.py --- LimitSwap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index c334a05..bd80d0d 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -815,7 +815,7 @@ def auth(): client2 = Web3(Web3.HTTPProvider(my_provider2)) print(timestamp(), "Connected to Ethereum BlockChain =", client2.isConnected()) # Insert LIMITSWAP Token Contract Here To Calculate Staked Verification - address = Web3.toChecksumAddress("0xab95e915c123fded5bdfb6325e35ef5515f1ea69") + address = Web3.toChecksumAddress("0x1712aad2c773ee04bdc9114b32163c058321cd85") abi = standardAbi balanceContract = client2.eth.contract(address=address, abi=abi) decimals = balanceContract.functions.decimals().call() @@ -842,7 +842,7 @@ def approve(address, amount): eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') - if eth_balance > 0.00005: + if eth_balance > 0.05: print("Estimating Gas Cost Using Web3") if settings['EXCHANGE'].lower() == 'uniswap': print("Estimating Gas Cost Using Web3") @@ -1835,7 +1835,7 @@ def run(): eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') - if eth_balance > 0.000005: + if eth_balance > 0.05: pass else: print( From e944fe68e2e618eb6a4075ecf552ba3d8b6e3336 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:15:51 +0100 Subject: [PATCH 08/16] Update LimitSwap.py --- LimitSwap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LimitSwap.py b/LimitSwap.py index bd80d0d..937611f 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -192,7 +192,7 @@ def load_tokens_file(tokens_path, load_message=True): 'MAXTOKENS': 0, 'MOONBAG': 0, 'SELLAMOUNTINTOKENS': 'all', - 'GAS': 20, + 'GAS': 8, 'BOOSTPERCENT': 50, 'GASLIMIT': 1000000 From 7948cec528526c7830eb5994ca1a0d8ce18763d8 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:27:47 +0100 Subject: [PATCH 09/16] Update LimitSwap.py --- LimitSwap.py | 2171 +------------------------------------------------- 1 file changed, 3 insertions(+), 2168 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 937611f..72b4b67 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -192,7 +192,7 @@ def load_tokens_file(tokens_path, load_message=True): 'MAXTOKENS': 0, 'MOONBAG': 0, 'SELLAMOUNTINTOKENS': 'all', - 'GAS': 8, + 'GAS': 20, 'BOOSTPERCENT': 50, 'GASLIMIT': 1000000 @@ -921,14 +921,14 @@ def check_approval(address, balance): else: print(style.YELLOW + "\n ---------------------------------------------------------------------------\n" " You need to APPROVE this token before selling it : LimitSwap will do it now\n" - " ---------------------------------------------------------------------------\n") + " ---------------------------------------------------------------------------") print(style.RESET + "\n") tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) wait_for_tx(tx, address, False) print(style.GREEN + "\n ---------------------------------------------------------\n" " Token is now approved : LimitSwap will make a BUY order\n" - " ---------------------------------------------------------\n") + " ---------------------------------------------------------") print(style.RESET + "\n") return @@ -2170,2168 +2170,3 @@ def run(): sleep(1) if nonce > timeout: run() - -# -*- coding: utf-8 -*- -from web3 import Web3 -from time import sleep, time -import json -from decimal import Decimal -import os -from web3.exceptions import ABIFunctionNotFound, TransactionNotFound, BadFunctionCallOutput -import logging -from datetime import datetime -import sys -import requests -import cryptocode, re, pwinput -import argparse -import signal - -# DEVELOPER CONSIDERATIONS -# -# USER INTERACTION - Do not depend on user interaction. If you develop a setting that is going to require -# user interaction while the bot is running, warn the user before hand. Accept a value before the check -# for liquidity, and provide a command line flag. Basically, provide ways for the bot to continue it's -# entire process from buying all the way to selling multiple positions and multiple pairs with zero user -# interaction. -# -# HANDLING NEW ENTRIES IN settings.json - When adding a new configuration item in settings.json be sure to -# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file. -# Do not assume a user has changed their settings.json file to work with the new version, your additions -# should be backwards compatible and have safe default values if possible -# -# HANDLING NEW ENTRIES IN tokens.json - When adding a new configuration item in tokens.json be sure to -# review comment "COMMAND LINE ARGUMENTS" and the functions load_settings_file and save_settings_file -# Do not assume a user has changed their tokens.json file to work with the new version, your additions -# should be backwards compatible and have safe default values if possible - - -# initialization of number of failed transactions -failedtransactionsamount = 0 - - -# color styles -class style(): # Class of different text colours - default is white - BLACK = '\033[30m' - RED = '\033[31m' - GREEN = '\033[32m' - YELLOW = '\033[33m' - BLUE = '\033[34m' - MAGENTA = '\033[35m' - CYAN = '\033[36m' - WHITE = '\033[37m' - UNDERLINE = '\033[4m' - RESET = '\033[0m' - - -# Function to cleanly exit on SIGINT -def signal_handler(sig, frame): - sys.exit(0) - - -signal.signal(signal.SIGINT, signal_handler) - - -def timestamp(): - timestamp = time() - dt_object = datetime.fromtimestamp(timestamp) - return dt_object - - -# -# COMMAND LINE ARGUMENTS -# - -parser = argparse.ArgumentParser() -parser.add_argument("-p", "--password", type=str, - help="Password to decrypt private keys (WARNING: your password could be saved in your command prompt history)") -parser.add_argument("-s", "--settings", type=str, help="Specify the file to user for settings (default: settings.json)", - default="./settings.json") -parser.add_argument("-t", "--tokens", type=str, - help="Specify the file to use for tokens to trade (default: tokens.json)", default="./tokens.json") -parser.add_argument("-v", "--verbose", action='store_true', help="Print detailed messages to stdout") -command_line_args = parser.parse_args() - - -def printt(*print_args): - # Function: printt - # ---------------------------- - # provides normal print() functionality but also prints our timestamp - # - # returns: nothing - - print(timestamp(), ' '.join(map(str, print_args))) - - -def printt_v(*print_args): - # Function: printt - # ---------------------------- - # provides normal print() functionality but also prints our timestamp and pays attention to user set verbosity. - # - # returns: nothing - - if command_line_args.verbose == True: - print(timestamp(), ' '.join(map(str, print_args))) - - -def printt_err(*print_args): - # Function: printt_err - # -------------------- - # provides normal print() functionality but also prints our timestamp and the text highlighted to display an error - # - # returns: nothing - - print(timestamp(), " ", style.RED, ' '.join(map(str, print_args)), style.RESET, sep="") - - -def load_settings_file(settings_path, load_message=True): - # Function: load_settings_file - # ---------------------------- - # loads the settings file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file - # exits with an error message if necessary variables are not found in the settings files - # - # settings_path = the path of the file to load settings from - # - # returns: a dictionary with the settings from the file loaded - - if load_message == True: - print(timestamp(), "Loading settings from", command_line_args.settings) - - f = open(command_line_args.settings, ) - settings = json.load(f)[0] - f.close() - - for default_false in ['UNLIMITEDSLIPPAGE', 'USECUSTOMNODE']: - if default_false not in settings: - printt_v(default_false, "not found in settings configuration file, settings a default value of false.") - settings[default_false] = "false" - else: - settings[default_false] = settings[default_false].lower() - - for default_true in ['PREAPPROVE']: - if default_true not in settings: - printt_v(default_true, "not found in settings configuration file, settings a default value of true.") - settings[default_true] = "true" - else: - settings[default_true] = settings[default_true].lower() - - # Keys that must be set - for required_key in ['EXCHANGE']: - if required_key not in settings: - printt_err(required_key, "not found in settings configuration file.") - exit(-1) - else: - settings[required_key] = settings[required_key].lower() - - return settings - - -def load_tokens_file(tokens_path, load_message=True): - # Function: load_tokens_File - # ---------------------------- - # loads the token definition file defined by command_line_args.settings, sets sane defaults if variables aren't found in settings file - # exits with an error message if necessary variables are not found in the settings files - # - # tokens_path: the path of the file to load tokens from - # - # returns: a dictionary with the settings from the file loaded - - if load_message == True: - print(timestamp(), "Loading tokens from", command_line_args.tokens) - - s = open(command_line_args.tokens, ) - tokens = json.load(s) - s.close() - - # Make sure all values are lowercase - for token in tokens: - - for default_false in ['ENABLED', 'LIQUIDITYCHECK', 'LIQUIDITYINNATIVETOKEN', 'USECUSTOMBASEPAIR', 'HASFEES']: - if default_false not in token: - printt_v(default_false, "not found in configuration file in configuration for to token", - token['SYMBOL'], "setting a default value of false") - token[default_false] = "false" - else: - token[default_false] = token[default_false].lower() - - # Keys that must be set - for required_key in ['ADDRESS', 'BUYAMOUNTINBASE', 'BUYPRICEINBASE', 'SELLPRICEINBASE']: - if required_key not in token: - printt_err(required_key, "not found in configuration file in configuration for to token", - token['SYMBOL']) - exit(-1) - - token_defaults = { - 'SLIPPAGE': 49, - 'MAXTOKENS': 0, - 'MOONBAG': 0, - 'SELLAMOUNTINTOKENS': 'all', - 'GAS': 20, - 'BOOSTPERCENT': 50, - 'GASLIMIT': 1000000 - - } - - for default_key in token_defaults: - if default_key not in token: - printt_v(default_key, "not found in configuration file in configuration for to token", token['SYMBOL'], - "setting a value of", token_defaults['default_key']) - token[default_key] = token_defaults[default_key] - elif default_key == 'SELLAMOUNTINTOKENS': - token_defaults[default_key] = token_defaults[default_key].lower() - - return tokens - - -""""""""""""""""""""""""""" -//PRELOAD -""""""""""""""""""""""""""" -print(timestamp(), "Preloading Data") -settings = load_settings_file(command_line_args.settings) - -directory = './abi/' -filename = "standard.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - standardAbi = json.load(json_file) - -directory = './abi/' -filename = "lp.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - lpAbi = json.load(json_file) - -directory = './abi/' -filename = "router.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - routerAbi = json.load(json_file) - -directory = './abi/' -filename = "factory2.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - factoryAbi = json.load(json_file) - -directory = './abi/' -filename = "koffee.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - koffeeAbi = json.load(json_file) - -directory = './abi/' -filename = "pangolin.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - pangolinAbi = json.load(json_file) - -directory = './abi/' -filename = "joeRouter.json" -file_path = os.path.join(directory, filename) -with open(file_path) as json_file: - joeRouter = json.load(json_file) - -""""""""""""""""""""""""""" -//ERROR LOGGING -""""""""""""""""""""""""""" -os.makedirs('./logs', exist_ok=True) - -if not os.path.exists('./logs/errors.log'): - open('./logs/errors.log', 'w').close() - -if not os.path.exists('./logs/exceptions.log'): - open('./logs/exceptions.log', 'w').close() - -log_format = '%(levelname)s: %(asctime)s %(message)s' -logging.basicConfig(filename='./logs/errors.log', - level=logging.INFO, - format=log_format) - -logger1 = logging.getLogger('1') -logger1.addHandler(logging.FileHandler('./logs/exceptions.log')) - -logging.info("*************************************************************************************") -logging.info("For Help & To Learn More About how the bot works please visit our wiki here:") -logging.info("https://cryptognome.gitbook.io/limitswap/") -logging.info("*************************************************************************************") - -""""""""""""""""""""""""""" -//NETWORKS SELECT -""""""""""""""""""""""""""" - -if settings['EXCHANGE'].lower() == 'pancakeswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - print(timestamp(), 'Using custom node.') - else: - my_provider = "https://bsc-dataseed4.defibit.io" - - if not my_provider: - print(timestamp(), 'Custom node empty. Exiting') - exit(1) - - if my_provider[0].lower() == 'h': - print(timestamp(), 'Using HTTPProvider') - client = Web3(Web3.HTTPProvider(my_provider)) - elif my_provider[0].lower() == 'w': - print(timestamp(), 'Using WebsocketProvider') - client = Web3(Web3.WebsocketProvider(my_provider)) - else: - print(timestamp(), 'Using IPCProvider') - client = Web3(Web3.IPCProvider(my_provider)) - - print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - - if settings['EXCHANGEVERSION'] == "1": - routerAddress = Web3.toChecksumAddress("0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F") - factoryAddress = Web3.toChecksumAddress("0xbcfccbde45ce874adcb698cc183debcf17952812") - elif settings['EXCHANGEVERSION'] == "2": - routerAddress = Web3.toChecksumAddress("0x10ED43C718714eb63d5aA57B78B54704E256024E") - factoryAddress = Web3.toChecksumAddress("0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73") - - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") - base_symbol = "BNB" - rugdocchain = '&chain=bsc' - modified = False - -if settings['EXCHANGE'].lower() == 'traderjoe': - - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://api.avax.network/ext/bc/C/rpc" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "AVAX Smart Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - - routerAddress = Web3.toChecksumAddress("0x60aE616a2155Ee3d9A68541Ba4544862310933d4") - factoryAddress = Web3.toChecksumAddress("0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10") - - routerContract = client.eth.contract(address=routerAddress, abi=joeRouter) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7") - base_symbol = "AVAX" - rugdocchain = '&chain=avax' - modified = True - -elif settings['EXCHANGE'].lower() == 'pinkswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - print(timestamp(), 'Using custom node.') - else: - my_provider = "https://bsc-dataseed4.defibit.io" - - if not my_provider: - print(timestamp(), 'Custom node empty. Exiting') - exit(1) - - if my_provider[0].lower() == 'h': - print(timestamp(), 'Using HTTPProvider') - client = Web3(Web3.HTTPProvider(my_provider)) - elif my_provider[0].lower() == 'w': - print(timestamp(), 'Using WebsocketProvider') - client = Web3(Web3.WebsocketProvider(my_provider)) - else: - print(timestamp(), 'Using IPCProvider') - client = Web3(Web3.IPCProvider(my_provider)) - - print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) - print(timestamp(), "Loading PinkSwap Smart Contracts...") - - routerAddress = Web3.toChecksumAddress("0x319EF69a98c8E8aAB36Aea561Daba0Bf3D0fa3ac") - factoryAddress = Web3.toChecksumAddress("0x7d2ce25c28334e40f37b2a068ec8d5a59f11ea54") - - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - - weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") - base_symbol = "BNB" - rugdocchain = '&chain=bsc' - modified = False - -elif settings['EXCHANGE'].lower() == 'biswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - print(timestamp(), 'Using custom node.') - else: - my_provider = "https://bsc-dataseed4.defibit.io" - - if not my_provider: - print(timestamp(), 'Custom node empty. Exiting') - exit(1) - - if my_provider[0].lower() == 'h': - print(timestamp(), 'Using HTTPProvider') - client = Web3(Web3.HTTPProvider(my_provider)) - elif my_provider[0].lower() == 'w': - print(timestamp(), 'Using WebsocketProvider') - client = Web3(Web3.WebsocketProvider(my_provider)) - else: - print(timestamp(), 'Using IPCProvider') - client = Web3(Web3.IPCProvider(my_provider)) - - print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) - print(timestamp(), "Loading PinkSwap Smart Contracts...") - - routerAddress = Web3.toChecksumAddress("0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8") - factoryAddress = Web3.toChecksumAddress("0x858E3312ed3A876947EA49d572A7C42DE08af7EE") - - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - - weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") - base_symbol = "BNB" - rugdocchain = '&chain=bsc' - modified = False - -elif settings['EXCHANGE'].lower() == 'apeswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://bsc-dataseed4.defibit.io" - - client = Web3(Web3.HTTPProvider(my_provider)) - - print(timestamp(), "Binance Smart Chain Connected =", client.isConnected()) - print(timestamp(), "Loading ApeSwap Smart Contracts...") - - routerAddress = Web3.toChecksumAddress("0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7") - factoryAddress = Web3.toChecksumAddress("0x0841BD0B734E4F5853f0dD8d7Ea041c241fb0Da6") - - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - - weth = Web3.toChecksumAddress("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") - busd = Web3.toChecksumAddress("0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56") - base_symbol = "BNB" - rugdocchain = '&chain=bsc' - modified = False - -elif settings["EXCHANGE"].lower() == 'uniswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://pedantic-montalcini:lair-essay-ranger-rigid-hardy-petted@nd-857-678-344.p2pify.com" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "Uniswap Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D") - factoryAddress = Web3.toChecksumAddress("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - base_symbol = "ETH" - rugdocchain = '&chain=eth' - modified = False - -elif settings["EXCHANGE"].lower() == 'kuswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://rpc-mainnet.kcc.network" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "Kucoin Chain Connected =", client.isConnected()) - print(timestamp(), "Loading KuSwap Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0xa58350d6dee8441aa42754346860e3545cc83cda") - factoryAddress = Web3.toChecksumAddress("0xAE46cBBCDFBa3bE0F02F463Ec5486eBB4e2e65Ae") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x4446Fc4eb47f2f6586f9fAAb68B3498F86C07521") - base_symbol = "KCS" - rugdocchain = '&chain=kcc' - modified = False - -elif settings["EXCHANGE"].lower() == 'koffeeswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://rpc-mainnet.kcc.network" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "Kucoin Chain Connected =", client.isConnected()) - print(timestamp(), "Loading KoffeeSwap Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0xc0fFee0000C824D24E0F280f1e4D21152625742b") - factoryAddress = Web3.toChecksumAddress("0xC0fFeE00000e1439651C6aD025ea2A71ED7F3Eab") - routerContract = client.eth.contract(address=routerAddress, abi=koffeeAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x4446Fc4eb47f2f6586f9fAAb68B3498F86C07521") - base_symbol = "KCS" - rugdocchain = '&chain=kcc' - modified = True - -elif settings["EXCHANGE"].lower() == 'spookyswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://rpcapi.fantom.network" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "FANTOM Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0xF491e7B69E4244ad4002BC14e878a34207E38c29") - factoryAddress = Web3.toChecksumAddress("0x152eE697f2E276fA89E96742e9bB9aB1F2E61bE3") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83") - base_symbol = "FTM" - rugdocchain = '&chain=ftm' - modified = False - -elif settings["EXCHANGE"].lower() == 'spiritswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://rpcapi.fantom.network" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "FANTOM Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0x16327E3FbDaCA3bcF7E38F5Af2599D2DDc33aE52") - factoryAddress = Web3.toChecksumAddress("0xEF45d134b73241eDa7703fa787148D9C9F4950b0") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83") - base_symbol = "FTM" - rugdocchain = '&chain=ftm' - modified = False - -elif settings["EXCHANGE"].lower() == 'quickswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://polygon-rpc.com" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "Matic Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff") - factoryAddress = Web3.toChecksumAddress("0x5757371414417b8c6caad45baef941abc7d3ab32") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270") - base_symbol = "MATIC" - rugdocchain = '&chain=poly' - modified = False - -elif settings["EXCHANGE"].lower() == 'waultswap': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://rpc-waultfinance-mainnet.maticvigil.com/v1/0bc1bb1691429f1eeee66b2a4b919c279d83d6b0" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "Matic Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0x3a1D87f206D12415f5b0A33E786967680AAb4f6d") - factoryAddress = Web3.toChecksumAddress("0xa98ea6356A316b44Bf710D5f9b6b4eA0081409Ef") - routerContract = client.eth.contract(address=routerAddress, abi=routerAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270") - base_symbol = "MATIC" - rugdocchain = '&chain=poly' - modified = False - -elif settings["EXCHANGE"].lower() == 'pangolin': - if settings['USECUSTOMNODE'].lower() == 'true': - my_provider = settings['CUSTOMNODE'] - else: - my_provider = "https://api.avax.network/ext/bc/C/rpc" - - client = Web3(Web3.HTTPProvider(my_provider)) - print(timestamp(), "AVAX Chain Connected =", client.isConnected()) - print(timestamp(), "Loading Smart Contracts...") - routerAddress = Web3.toChecksumAddress("0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106") - factoryAddress = Web3.toChecksumAddress("0xefa94DE7a4656D787667C749f7E1223D71E9FD88") - routerContract = client.eth.contract(address=routerAddress, abi=pangolinAbi) - factoryContract = client.eth.contract(address=factoryAddress, abi=factoryAbi) - weth = Web3.toChecksumAddress("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7") - base_symbol = "AVAX" - rugdocchain = '&chain=avax' - modified = True - - -def get_password(): - # Function: get_password - # ---------------------------- - # Handles the decision making logic concerning private key encryption and asking the user for their password. - # - # returns: the user's password - - settings_changed = False - setnewpassword = False - - # Check to see if the user has a version of the settings file before private key encryption existed - if 'ENCRYPTPRIVATEKEYS' not in settings: - response = "" - settings_changed = True - while response != "y" and response != "n": - print("\nWould you like to use a password to encrypt your private keys?") - response = input("You will need to input this password each time LimitSwap is executed (y/n): ") - - if response == "y": - settings['ENCRYPTPRIVATEKEYS'] = "true" - setnewpassword = True - else: - settings['ENCRYPTPRIVATEKEYS'] = "false" - - # If the user wants to encrypt their private keys, but we don't have an encrypted private key recorded, we need to ask for a password - elif settings['ENCRYPTPRIVATEKEYS'] == "true" and not settings['PRIVATEKEY'].startswith('aes:'): - print("\nPlease create a password to encrypt your private keys.") - setnewpassword = True - - # Set a new password when necessary - if setnewpassword == True: - settings_changed = True - passwords_differ = True - while passwords_differ: - pwd = pwinput.pwinput(prompt="\nType your new password: ") - pwd2 = pwinput.pwinput(prompt="\nType your new password again: ") - - if pwd != pwd2: - print("Error, password mismatch. Try again.") - else: - passwords_differ = False - - # The user already has encrypted private keys. Accept a password so we can unencrypt them - elif settings['ENCRYPTPRIVATEKEYS'] == "true": - - if command_line_args.password: - pwd = command_line_args.password - else: - pwd = pwinput.pwinput(prompt="\nPlease specify the password to decrypt your keys: ") - - else: - pwd = "" - - if not pwd.strip(): - print() - print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") - print("X You are running LimitSwap without encrypting your private keys. X") - print("X Private keys are stored on disk unencrypted and can be accessed by X") - print("X anyone with access to the file system, including the Systems/VPS administrator X") - print("X and anyone with physical access to the machine or hard drives. X") - print("X WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING =-= WARNING=-= WARNING X") - print() - - if settings_changed == True: - save_settings(settings, pwd) - - return pwd - - -# RUGDOC CONTROL IMPLEMENTATION -# Honeypot API details -honeypot_url = 'https://honeypot.api.rugdoc.io/api/honeypotStatus.js?address=' - -# Rugdoc's answers interpretations -interpretations = { - "UNKNOWN": (style.RED + '\nThe status of this token is unknown. ' - 'This is usually a system error but could \n also be a bad sign for the token. Be careful.'), - "OK": (style.GREEN + '\nRUGDOC API RESULT : OK \n' - '√ Honeypot tests passed. RugDoc program was able to buy and sell it successfully. This however does not guarantee that it is not a honeypot.'), - "NO_PAIRS": (style.RED + '\nRUGDOC API RESULT : NO_PAIRS \n' - '⚠ Could not find any trading pair for this token on the default router and could thus not test it.'), - "SEVERE_FEE": (style.RED + '\nRUGDOC API RESULT : SEVERE_FEE \n' - '/!\ /!\ A severely high trading fee (over 50%) was detected when selling or buying this token.'), - "HIGH_FEE": (style.YELLOW + '\nRUGDOC API RESULT : HIGH_FEE \n' - '/!\ /!\ A high trading fee (Between 20% and 50%) was detected when selling or buying this token. Our system was however able to sell the token again.'), - "MEDIUM_FEE": (style.YELLOW + '\nRUGDOC API RESULT : MEDIUM_FEE \n' - '/!\ A trading fee of over 10% but less then 20% was detected when selling or buying this token. Our system was however able to sell the token again.'), - "APPROVE_FAILED": (style.RED + '\nRUGDOC API RESULT : APPROVE_FAILED \n' - '/!\ /!\ /!\ Failed to approve the token.\n This is very likely a honeypot.'), - "SWAP_FAILED": (style.RED + '\nRUGDOC API RESULT : SWAP_FAILED \n' - '/!\ /!\ /!\ Failed to sell the token. \n This is very likely a honeypot.'), - "chain not found": (style.RED + '\nRUGDOC API RESULT : chain not found \n' - '/!\ Sorry, rugdoc API does not work on this chain... (it does not work on ETH, mainly) \n') -} - - -# Function to check rugdoc API -def honeypot_check(address): - url = (honeypot_url + address + rugdocchain) - # sending get request and saving the response as response object - return requests.get(url) - - -def save_settings(settings, pwd): - if len(pwd) > 0: - encrypted_settings = settings.copy() - encrypted_settings['LIMITWALLETPRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['LIMITWALLETPRIVATEKEY'], - pwd) - encrypted_settings['PRIVATEKEY'] = 'aes:' + cryptocode.encrypt(settings['PRIVATEKEY'], pwd) - - # TODO: MASSAGE OUTPUT - LimitSwap currently loads settings.json as a [0] element, so we need to massage our - # settings.json output so that it's reasable. This should probably be fixed by us importing - # the entire json file, instead of just the [0] element. - - print(timestamp(), "Writing settings to file.") - - if settings['ENCRYPTPRIVATEKEYS'] == "true": - output_settings = encrypted_settings - else: - output_settings = settings - - with open(command_line_args.settings, 'w') as f: - f.write("[\n") - f.write(json.dumps(output_settings, indent=4)) - f.write("\n]\n") - - -def parse_wallet_settings(settings, pwd): - # Function: load_wallet_settings - # ---------------------------- - # Handles the process of deciding whether or not the user's private key needs to be decrypted - # Accepts user input for new private keys and wallet addresses - # - # returns: none (exits on incorrect password) - - settings_changed = False - - # Check for limit wallet information - if " " in settings['LIMITWALLETADDRESS'] or settings['LIMITWALLETADDRESS'] == "": - settings_changed = True - settings['LIMITWALLETADDRESS'] = input("Please provide the wallet address where you have your LIMIT: ") - - # Check for limit wallet private key - if " " in settings['LIMITWALLETPRIVATEKEY'] or settings['LIMITWALLETPRIVATEKEY'] == "": - settings_changed = True - settings['LIMITWALLETPRIVATEKEY'] = input( - "Please provide the private key for the wallet where you have your LIMIT: ") - - # If the limit wallet private key is already set and encrypted, decrypt it - elif settings['LIMITWALLETPRIVATEKEY'].startswith('aes:'): - printt("Decrypting limit wallet private key.") - settings['LIMITWALLETPRIVATEKEY'] = settings['LIMITWALLETPRIVATEKEY'].replace('aes:', "", 1) - settings['LIMITWALLETPRIVATEKEY'] = cryptocode.decrypt(settings['LIMITWALLETPRIVATEKEY'], pwd) - - if settings['LIMITWALLETPRIVATEKEY'] == False: - print(style.RED + "ERROR: Your private key decryption password is incorrect") - print(style.RESET + "Please re-launch the bot and try again") - sleep(10) - sys.exit() - - # Check for trading wallet information - if " " in settings['WALLETADDRESS'] or settings['WALLETADDRESS'] == "": - settings_changed = True - settings['WALLETADDRESS'] = input("Please provide the wallet address for your trading wallet: ") - - # Check for trading wallet private key - if " " in settings['PRIVATEKEY'] or settings['PRIVATEKEY'] == "": - settings_changed = True - settings['PRIVATEKEY'] = input("Please provide the private key for the wallet you want to trade with: ") - - # If the trading wallet private key is already set and encrypted, decrypt it - elif settings['PRIVATEKEY'].startswith('aes:'): - print(timestamp(), "Decrypting limit wallet private key.") - settings['PRIVATEKEY'] = settings['PRIVATEKEY'].replace('aes:', "", 1) - settings['PRIVATEKEY'] = cryptocode.decrypt(settings['PRIVATEKEY'], pwd) - - if settings_changed == True: - save_settings(settings, pwd) - - -def decimals(address): - try: - balanceContract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) - decimals = balanceContract.functions.decimals().call() - DECIMALS = 10 ** decimals - except ABIFunctionNotFound: - DECIMALS = 10 ** 18 - except ValueError as ve: - logging.exception(ve) - print("Please check your SELLPRICE values.") - return DECIMALS - - -def check_logs(): - print(timestamp(), "Quickly Checking Log Size") - with open('./logs/errors.log') as f: - line_count = 0 - for line in f: - line_count += 1 - if line_count > 100: - with open('./logs/errors.log', "r") as f: - lines = f.readlines() - - with open('./logs/errors.log', "w") as f: - f.writelines(lines[20:]) - - f.close() - - -def decode_key(): - private_key = settings['LIMITWALLETPRIVATEKEY'] - acct = client.eth.account.privateKeyToAccount(private_key) - addr = acct.address - return addr - - -def check_release(): - try: - url = 'https://api.github.com/repos/CryptoGnome/LimitSwap/releases/latest' - r = requests.get(url).json()['tag_name'] - print("Checking Latest Release Version on Github, Please Make Sure You are Staying Updated = ", r) - logging.info("Checking Latest Release Version on Github, Please Make Sure You are Staying Updated = " + r) - except Exception: - r = "github api down, please ignore" - - return r - - -def auth(): - my_provider2 = 'https://reverent-raman:photo-hamlet-ankle-saved-scared-bobbed@nd-539-402-515.p2pify.com' - client2 = Web3(Web3.HTTPProvider(my_provider2)) - print(timestamp(), "Connected to Ethereum BlockChain =", client2.isConnected()) - # Insert LIMITSWAP Token Contract Here To Calculate Staked Verification - address = Web3.toChecksumAddress("0x1712aad2c773ee04bdc9114b32163c058321cd85") - abi = standardAbi - balanceContract = client2.eth.contract(address=address, abi=abi) - decimals = balanceContract.functions.decimals().call() - DECIMALS = 10 ** decimals - - # Exception for incorrect Key Input - try: - decode = decode_key() - except Exception: - print("There is a problem with your private key : please check if it's correct. Don't enter seed phrase !") - logging.info( - "There is a problem with your private key : please check if it's correct. Don't enter seed phrase !") - - wallet_address = Web3.toChecksumAddress(decode) - balance = balanceContract.functions.balanceOf(wallet_address).call() - true_balance = balance / DECIMALS - print(timestamp(), "Current Tokens Staked =", true_balance) - logging.info("Current Tokens Staked = " + str(true_balance)) - return true_balance - - -def approve(address, amount): - print(timestamp(), "Approving", address) - - eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') - - if eth_balance > 0.05: - print("Estimating Gas Cost Using Web3") - if settings['EXCHANGE'].lower() == 'uniswap': - print("Estimating Gas Cost Using Web3") - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price =", gas) - - elif settings['EXCHANGE'].lower() == 'pancakeswap': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - elif settings['EXCHANGE'].lower() == 'spiritswap': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - elif settings['EXCHANGE'].lower() == 'spookyswap': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - elif settings['EXCHANGE'].lower() == 'pangolin': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - elif settings['EXCHANGE'].lower() == 'quickswap': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - elif settings['EXCHANGE'].lower() == 'kuswap' or 'koffeeswap': - gas = (((client.eth.gasPrice) / 1000000000)) + ((client.eth.gasPrice) / 1000000000) * (int(20) / 100) - print("Current Gas Price = ", gas) - else: - print("EXCHANGE NAME IN SETTINGS IS SPELLED INCORRECTLY OR NOT SUPPORTED YET CHECK WIKI!") - logging.info("EXCHANGE NAME IN SETTINGS IS SPELLED INCORRECTLY OR NOT SUPPORTED YET CHECK WIKI!") - exit() - - contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) - transaction = contract.functions.approve(routerAddress, amount).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': 300000, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) - - try: - return client.eth.sendRawTransaction(signed_txn.rawTransaction) - finally: - print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) - # LOG TX TO JSON - with open('./transactions.json', 'r') as fp: - data = json.load(fp) - tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) - tx_input = {"hash": tx_hash} - data.append(tx_input) - with open('./transactions.json', 'w') as fp: - json.dump(data, fp, indent=2) - fp.close() - - return tx_hash - else: - print(timestamp(), - "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") - logging.info( - "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") - sleep(10) - sys.exit() - - -def check_approval(address, balance): - print(timestamp(), "Checking Approval Status", address) - contract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) - allowance = contract.functions.allowance(Web3.toChecksumAddress(settings['WALLETADDRESS']), routerAddress).call() - - if int(allowance) < int(balance): - - if settings["EXCHANGE"].lower() == 'quickswap': - print("Revert to Zero To change approval") - tx = approve(address, 0) - wait_for_tx(tx, address, False) - tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) - wait_for_tx(tx, address, False) - else: - tx = approve(address, 115792089237316195423570985008687907853269984665640564039457584007913129639934) - wait_for_tx(tx, address, False) - - return - - else: - pass - - -def check_bnb_balance(): - balance = client.eth.getBalance(settings['WALLETADDRESS']) - print(timestamp(), "Current Wallet Balance is :", Web3.fromWei(balance, 'ether'), base_symbol) - return balance - - -def check_balance(address, symbol): - address = Web3.toChecksumAddress(address) - DECIMALS = decimals(address) - balanceContract = client.eth.contract(address=address, abi=standardAbi) - balance = balanceContract.functions.balanceOf(settings['WALLETADDRESS']).call() - print(timestamp(), "Current Wallet Balance is: " + str(balance / DECIMALS) + " " + symbol) - - return balance - - -def fetch_pair(inToken, outToken): - print(timestamp(), "Fetching Pair Address") - pair = factoryContract.functions.getPair(inToken, outToken).call() - print(timestamp(), "Pair Address = ", pair) - return pair - - -def sync(inToken, outToken): - pair = factoryContract.functions.getPair(inToken, outToken).call() - syncContract = client.eth.contract(address=Web3.toChecksumAddress(pair), abi=lpAbi) - sync = syncContract.functions.sync().call() - - -def check_pool(inToken, outToken, symbol): - # This function is made to calculate Liquidity of a token - pair_address = factoryContract.functions.getPair(inToken, outToken).call() - DECIMALS = decimals(outToken) - pair_contract = client.eth.contract(address=pair_address, abi=lpAbi) - reserves = pair_contract.functions.getReserves().call() - pooled = reserves[1] / DECIMALS - # print("Debug LIQUIDITYAMOUNT line 627 :", pooled, "in token:", outToken) - - return pooled - - -def check_price(inToken, outToken, symbol, base, custom, routing, buypriceinbase, sellpriceinbase): - # CHECK GET RATE OF THE TOKEn - - DECIMALS = decimals(inToken) - stamp = timestamp() - - if custom.lower() == 'false': - base = base_symbol - else: - pass - - if routing == 'true': - if outToken != weth: - price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth, outToken]).call()[-1] - DECIMALS = decimals(outToken) - tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, - "//// your sellprice =", sellpriceinbase, base) - else: - price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] - DECIMALS = decimals(outToken) - tokenPrice = price_check / DECIMALS - price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, - "//// your sellprice =", sellpriceinbase, base) - - else: - if outToken != weth: - price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, outToken]).call()[-1] - DECIMALS = decimals(outToken) - tokenPrice = price_check / DECIMALS - print(stamp, symbol, " Price ", tokenPrice, base, "//// your buyprice =", buypriceinbase, base, - "//// your sellprice =", sellpriceinbase, base) - else: - price_check = routerContract.functions.getAmountsOut(1 * DECIMALS, [inToken, weth]).call()[-1] - DECIMALS = decimals(outToken) - tokenPrice = price_check / DECIMALS - price_output = "{:.18f}".format(tokenPrice) - print(stamp, symbol, "Price =", price_output, base, "//// your buyprice =", buypriceinbase, base, - "//// your sellprice =", sellpriceinbase, base) - - return tokenPrice - - -def wait_for_tx(tx_hash, address, check): - print(timestamp(), "............Waiting 1 minute for TX to Confirm............") - timeout = time() + 60 - while True: - print(timestamp(), "............Waiting 1 minute for TX to Confirm............") - sleep(1) - try: - txn_receipt = client.eth.getTransactionReceipt(tx_hash) - return txn_receipt['status'] - - except Exception as e: - txn_receipt = None - - if txn_receipt is not None and txn_receipt['blockHash'] is not None: - return txn_receipt['status'] - - elif time() > timeout: - print(style.RED + "\n") - print(timestamp(), "Transaction was not confirmed after 1 minute : something wrong happened.\n" - "Please check if :\n" - "- your node is running correctly\n" - "- you have enough Gaslimit (check 'Gas Used by Transaction') if you have a failed Tx") - print(style.RESET + "\n") - failedtransactionsamount += 1 - logging.info("Transaction was not confirmed after 1 minute, breaking Check Cycle....") - sleep(5) - break - - # loop to check for balance after purchase - if check == True: - timeout = time() + 30 - print(style.RESET + "\n") - - while True: - print(timestamp(), ".........Waiting 30s to check tokens balance in your wallet after purchase............") - sleep(1) - - balance = check_balance(address, address) - - if balance > 0: - break - elif time() > timeout: - print(timestamp(), - "NO BUY FOUND, WE WILL CHECK A FEW TIMES TO SEE IF THERE IS BLOCKCHAIN DELAY, IF NOT WE WILL ASSUME THE TX HAS FAILED") - logging.info( - "NO BUY FOUND, WE WILL CHECK A FEW TIMES TO SEE IF THERE IS BLOCKCHAIN DELAY, IF NOT WE WILL ASSUME THE TX HAS FAILED") - break - - -def preapprove(tokens): - for token in tokens: - check_approval(token['ADDRESS'], 115792089237316195423570985008687907853269984665640564039457584007913129639934) - - if token['USECUSTOMBASEPAIR'].lower() == 'false': - check_approval(weth, 115792089237316195423570985008687907853269984665640564039457584007913129639934) - else: - check_approval(token['BASEADDRESS'], - 115792089237316195423570985008687907853269984665640564039457584007913129639934) - - -def buy(amount, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, base, routing, waitseconds, - failedtransactionsnumber): - seconds = int(waitseconds) - if int(failedtransactionsamount) == int(failedtransactionsnumber): - print( - style.RED + "\n ---------------------------------------------------------------\n" - " Bot has reached maximum FAILED TRANSACTIONS number: it stops\n" - " ---------------------------------------------------------------\n\n") - - logging.info("Bot has reached maximum FAILED TRANSACTIONS number: it stops") - sleep(10) - sys.exit() - else: - - if waitseconds != '0': - print("Bot will wait", waitseconds, " seconds before buy, as you entered in BUYAFTER_XXX_SECONDS parameter") - sleep(seconds) - - print(timestamp(), "Placing New Buy Order for " + symbol) - - if int(gaslimit) < 250000: - print( - "Your GASLIMIT parameter is too low : LimitSwap has forced it to 300000 otherwise your transaction would fail for sure. We advise you to raise it to 1000000.") - gaslimit = 300000 - - if custom.lower() == 'false': - balance = Web3.fromWei(check_bnb_balance(), 'ether') - base = base_symbol - else: - address = Web3.toChecksumAddress(inToken) - DECIMALS = decimals(address) - balance_check = check_balance(inToken, base) - balance = balance_check / DECIMALS - - if balance > Decimal(amount): - if gas.lower() == 'boost': - gas_check = client.eth.gasPrice - gas_price = gas_check / 1000000000 - gas = (gas_price * ((int(boost)) / 100)) + gas_price - else: - gas = int(gas) - - gaslimit = int(gaslimit) - slippage = int(slippage) - DECIMALS = decimals(inToken) - amount = int(float(amount) * DECIMALS) - - if custom.lower() == 'false': - # if USECUSTOMBASEPAIR = false - amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - - deadline = int(time() + + 60) - - # THIS SECTION IS FOR MODIFIED CONTRACTS : EACH EXCHANGE NEEDS TO BE SPECIFIED - # USECUSTOMBASEPAIR = false - if modified == True: - - if settings["EXCHANGE"].lower() == 'koffeeswap': - transaction = routerContract.functions.swapExactKCSForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'value': amount, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': - transaction = routerContract.functions.swapExactAVAXForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'value': amount, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - - else: - # USECUSTOMBASEPAIR = false - # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. - - # Special condition on Uniswap, to implement EIP-1559 - if settings["EXCHANGE"].lower() == 'uniswap': - transaction = routerContract.functions.swapExactETHForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # USECUSTOMBASEPAIR = false - # for all the rest of exchanges with Modified = false - transaction = routerContract.functions.swapExactETHForTokens( - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'value': amount, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # USECUSTOMBASEPAIR = true - if inToken == weth: - # USECUSTOMBASEPAIR = true - # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address - amount_out = routerContract.functions.getAmountsOut(amount, [weth, outToken]).call()[-1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # LIQUIDITYINNATIVETOKEN = true - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - if routing.lower() == 'true': - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[ - -1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if settings["EXCHANGE"].lower() == 'uniswap': - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - # LIQUIDITYINNATIVETOKEN = true - - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - # LIQUIDITYINNATIVETOKEN = true - # Exchange different from Uniswap - - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] - if settings['UNLIMITEDSLIPPAGE'].lower() == 'true': - min_tokens = 100 - else: - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if settings["EXCHANGE"].lower() == 'uniswap': - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - # Special condition on Uniswap, to implement EIP-1559 - - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # Base Pair different from weth - # Exchange different from Uniswap - - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - sync(inToken, outToken) - signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) - - try: - return client.eth.sendRawTransaction(signed_txn.rawTransaction) - finally: - print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) - # LOG TX TO JSON - with open('./transactions.json', 'r') as fp: - data = json.load(fp) - tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) - tx_input = {"hash": tx_hash} - data.append(tx_input) - with open('./transactions.json', 'w') as fp: - json.dump(data, fp, indent=2) - fp.close() - - return tx_hash - - else: - print(timestamp(), "Not Enough " + base + " Balance to make buys") - logging.info("Not Enough " + base + " Balance to make buys") - return False - - -def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fees, custom, symbol, routing): - print(timestamp(), "Placing Sell Order " + symbol) - balance = Web3.fromWei(check_balance(inToken, symbol), 'ether') - check_approval(inToken, balance * 1000000000) - - if int(gaslimit) < 250000: - gaslimit = 300000 - - if type(amount) == str: - amount_check = balance - else: - amount_check = Decimal(amount) - - if balance >= Decimal(amount_check) and balance > 0.0000000000000001: - - if gas.lower() == 'boost': - gas_check = client.eth.gasPrice - gas_price = gas_check / 1000000000 - gas = (gas_price * ((int(boost) * 4) / 100)) + gas_price - else: - gas = int(gas) - - slippage = int(slippage) - gaslimit = int(gaslimit) - DECIMALS = decimals(inToken) - - if amount.lower() == 'all': - balance = check_balance(inToken, symbol) - moonbag = int(Decimal(moonbag) * DECIMALS) - amount = int(Decimal(balance - moonbag)) - - else: - balance = check_balance(inToken, symbol) - amount = Decimal(amount) * DECIMALS - moonbag = int(Decimal(moonbag) * DECIMALS) - - if balance < amount: - print(timestamp(), "Selling Remaining ", symbol) - amount = int(Decimal(balance - moonbag)) - else: - amount = int(Decimal(balance - moonbag)) - if amount > 0: - print(timestamp(), "Selling", amount / DECIMALS, symbol) - else: - print("Not enough left to sell, would bust moonbag") - amount = 0 - - if custom.lower() == 'false': - # USECUSTOMBASEPAIR = false - sync(inToken, weth) - - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if fees.lower() == 'true': - - # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED - if modified == True: - # USECUSTOMBASEPAIR = false - # HASFEES = true - - if settings["EXCHANGE"].lower() == 'koffeeswap': - transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - if settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': - transaction = routerContract.functions.swapExactTokensForAVAXSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # This section is for exchange with Modified = false --> uniswap / pancakeswap / apeswap, etc. - # USECUSTOMBASEPAIR = false - # HASFEES = true - transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - else: - # USECUSTOMBASEPAIR = false - # HASFEES = false - - # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED - if modified == True: - # USECUSTOMBASEPAIR = false - # HASFEES = false - # Modified = true - - if settings["EXCHANGE"].lower() == 'koffeeswap': - transaction = routerContract.functions.swapExactTokensForKCS( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': - transaction = routerContract.functions.swapExactTokensForAVAX( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # USECUSTOMBASEPAIR = false - # HASFEES = false - # Modified = false --> uniswap / pancakeswap / apeswap, etc. - - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForETH( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # for all the rest of exchanges with Modified = false - transaction = routerContract.functions.swapExactTokensForETH( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # USECUSTOMBASEPAIR = true - if outToken == weth: - # if user has set WETH or WBNB as Custom base pair - sync(inToken, outToken) - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth]).call()[-1] - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if fees.lower() == 'true': - # USECUSTOMBASEPAIR = true - # HASFEES = true - - if int(gaslimit) < 950000: - gaslimit = 950000 - - # THIS SECTION IS FOR MODIFIED CONTRACTS AND EACH EXCHANGE IS SPECIFIED - if modified == True: - # USECUSTOMBASEPAIR = true - # HASFEES = true - # Modified = true - - if settings["EXCHANGE"].lower() == 'koffeeswap': - transaction = routerContract.functions.swapExactTokensForKCSSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - elif settings["EXCHANGE"].lower() == 'pangolin' or settings["EXCHANGE"].lower() == 'traderjoe': - transaction = routerContract.functions.swapExactTokensForAVAXSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # USECUSTOMBASEPAIR = true - # HASFEES = true - # Modified = false - - transaction = routerContract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - else: - # USECUSTOMBASEPAIR = true - # HASFEES = false - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - - else: - sync(inToken, outToken) - - if routing.lower() == 'false' and outToken != weth: - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, outToken]).call()[-1] - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if fees.lower() == 'true': - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # HASFEES = true - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # for all the rest of exchanges - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # HASFEES = false - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - # for all the rest of exchanges - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - elif routing.lower() == 'false' and outToken == weth: - # LIQUIDITYINNATIVETOKEN = false - # USECUSTOMBASEPAIR = true - # but user chose to put WETH or WBNB contract as CUSTOMBASEPAIR address - print( - "ERROR IN YOUR TOKENS.JSON : YOU NEED TO CHOOSE THE PROPER BASE PAIR AS SYMBOL IF YOU ARE TRADING OUTSIDE OF NATIVE LIQUIDITY POOL") - - else: - amount_out = routerContract.functions.getAmountsOut(amount, [inToken, weth, outToken]).call()[-1] - min_tokens = int(amount_out * (1 - (slippage / 100))) - deadline = int(time() + + 60) - - if fees.lower() == 'true': - # HASFEES = true - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - - else: - transaction = routerContract.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - else: - # HASFEES = false - if settings["EXCHANGE"].lower() == 'uniswap': - # Special condition on Uniswap, to implement EIP-1559 - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'maxFeePerGas': Web3.toWei(gas, 'gwei'), - 'maxPriorityFeePerGas': Web3.toWei('1.5', 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']), - 'type': "0x02" - }) - else: - transaction = routerContract.functions.swapExactTokensForTokens( - amount, - min_tokens, - [inToken, weth, outToken], - Web3.toChecksumAddress(settings['WALLETADDRESS']), - deadline - ).buildTransaction({ - 'gasPrice': Web3.toWei(gas, 'gwei'), - 'gas': gaslimit, - 'from': Web3.toChecksumAddress(settings['WALLETADDRESS']), - 'nonce': client.eth.getTransactionCount(settings['WALLETADDRESS']) - }) - - sync(inToken, outToken) - signed_txn = client.eth.account.signTransaction(transaction, private_key=settings['PRIVATEKEY']) - - try: - return client.eth.sendRawTransaction(signed_txn.rawTransaction) - finally: - print(timestamp(), "Transaction Hash = ", Web3.toHex(client.keccak(signed_txn.rawTransaction))) - # LOG TX TO JSON - with open('./transactions.json', 'r') as fp: - data = json.load(fp) - tx_hash = client.toHex(client.keccak(signed_txn.rawTransaction)) - tx_input = {"hash": tx_hash} - data.append(tx_input) - with open('./transactions.json', 'w') as fp: - json.dump(data, fp, indent=2) - fp.close() - - return tx_hash - else: - pass - - -def run(): - global failedtransactionsamount - - try: - - tokens = load_tokens_file(command_line_args.tokens, True) - - eth_balance = Web3.fromWei(client.eth.getBalance(settings['WALLETADDRESS']), 'ether') - - if eth_balance > 0.05: - pass - else: - print( - style.RED + "\nYou have less than 0.05 ETH/BNB/FTM/MATIC/Etc. token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet") - logging.info( - "You have less than 0.05 ETH/BNB/FTM/MATIC or network gas token in your wallet, bot needs at least 0.05 to cover fees : please add some more in your wallet.") - sleep(10) - sys.exit() - - if settings['PREAPPROVE'].lower() == 'true': - preapprove(tokens) - else: - pass - - for token in tokens: - # Initialization of values, in case the user re-used some old tokens.json files - if 'RUGDOC_CHECK' not in token: - token['RUGDOC_CHECK'] = 'false' - if 'BUYAFTER_XXX_SECONDS' not in token: - token['BUYAFTER_XXX_SECONDS'] = 0 - if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 - # End of initialization of values - - if token['RUGDOC_CHECK'].lower() == 'true': - - honeypot = honeypot_check(address=token['ADDRESS']) - d = json.loads(honeypot.content) - for key, value in interpretations.items(): - if d["status"] in key: - honeypot_status = value - honeypot_code = key - print(honeypot_status) - - decision = "" - while decision != "y" and decision != "n": - print(style.RESET + "\nWhat is your decision?") - decision = input("Would you like to snipe this token? (y/n): ") - - if decision == "y": - print(style.RESET + "\nOK let's go!!\n") - pass - else: - sys.exit() - - else: - pass - - while True: - tokens = load_tokens_file(command_line_args.tokens, False) - - for token in tokens: - # Initialization of values, in case the user re-used some old tokens.json files - if 'RUGDOC_CHECK' not in token: - token['RUGDOC_CHECK'] = 'false' - if 'BUYAFTER_XXX_SECONDS' not in token: - token['BUYAFTER_XXX_SECONDS'] = 0 - if 'MAX_FAILED_TRANSACTIONS_IN_A_ROW' not in token: - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW'] = 2 - # End of initialization of values - - if token['ENABLED'].lower() == 'true': - inToken = Web3.toChecksumAddress(token['ADDRESS']) - - if token['USECUSTOMBASEPAIR'].lower() == 'true': - outToken = Web3.toChecksumAddress(token['BASEADDRESS']) - else: - outToken = weth - - try: - quote = check_price(inToken, outToken, token['SYMBOL'], token['BASESYMBOL'], - token['USECUSTOMBASEPAIR'], token['LIQUIDITYINNATIVETOKEN'], - token['BUYPRICEINBASE'], token['SELLPRICEINBASE']) - pool = check_pool(inToken, outToken, token['BASESYMBOL']) - # print("Debug Liquidity Reserves ligne 1267:", float(pool)) - # print("Debug inToken : ", inToken, "outToken :", outToken) - - except Exception: - print(timestamp(), token['SYMBOL'], - " Not Listed For Trade Yet... waiting for liquidity to be added on exchange") - quote = 0 - - if quote < Decimal(token['BUYPRICEINBASE']) and quote != 0: - balance = check_balance(inToken, token['SYMBOL']) - DECIMALS = decimals(inToken) - if Decimal(balance / DECIMALS) < Decimal(token['MAXTOKENS']): - - if token["LIQUIDITYCHECK"].lower() == 'true': - pool = check_pool(inToken, outToken, token['BASESYMBOL']) - print(timestamp(), "You have set LIQUIDITYCHECK = true.") - print(timestamp(), "Current", token['SYMBOL'], "Liquidity = ", int(pool), "in token:", - outToken) - - if float(token['LIQUIDITYAMOUNT']) <= float(pool): - print(timestamp(), "LIQUIDITYAMOUNT parameter =", int(token['LIQUIDITYAMOUNT']), - " --> Enough liquidity detected : Buy Signal Found!") - log_price = "{:.18f}".format(quote) - logging.info("BuySignal Found @" + str(log_price)) - tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], - token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], - token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], - token['BASESYMBOL'], token['LIQUIDITYINNATIVETOKEN'], - token['BUYAFTER_XXX_SECONDS'], token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) - - if tx != False: - tx = wait_for_tx(tx, token['ADDRESS'], True) - print( - style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") - print(style.RESET + "") - sleep(3) - check_balance(token['ADDRESS'], token['SYMBOL']) - print(style.RESET + "\n") - sleep(3) - - if tx != 1: - # transaction is a FAILURE - print( - style.RED + "\n -------------------------------------------------\n" - " FAILURE ! Plese check your wallet. \n" - " Cause of failure can be : \n" - " - GASLIMIT too low\n" - " - SLIPPAGE too low\n" - " -------------------------------------------------\n\n") - print(style.RESET + "") - failedtransactionsamount += 1 - preapprove(tokens) - else: - # transaction is a SUCCESS - print( - style.GREEN + "\n ----------------------------------\n" - " SUCCESS : your Tx is confirmed :)\n" - " ----------------------------------\n") - print(style.RESET + "") - pass - - else: - # print("debug 1450") - pass - else: - print(timestamp(), "LIQUIDITYAMOUNT parameter =", int(token['LIQUIDITYAMOUNT']), - " : not enough liquidity, bot will not buy") - - else: - print(timestamp(), "Buy Signal Found!") - log_price = "{:.18f}".format(quote) - logging.info("BuySignal Found @" + str(log_price)) - tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], token['SLIPPAGE'], - token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], - token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['BASESYMBOL'], - token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) - - if tx != False: - tx = wait_for_tx(tx, token['ADDRESS'], True) - print( - style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") - print(style.RESET + "") - sleep(3) - check_balance(token['ADDRESS'], token['SYMBOL']) - print(style.RESET + "\n") - sleep(3) - - if tx != 1: - # transaction is a FAILURE - print( - style.RED + "\n -------------------------------------------------\n" - " FAILURE ! Please check your wallet. \n" - " Cause of failure can be : \n" - " - GASLIMIT too low\n" - " - SLIPPAGE too low\n" - " -------------------------------------------------\n\n") - print(style.RESET + "") - failedtransactionsamount += 1 - preapprove(tokens) - else: - # transaction is a SUCCESS - print( - style.GREEN + "\n ----------------------------------\n" - " SUCCESS : your Tx is confirmed :)\n" - " ----------------------------------\n") - print(style.RESET + "") - pass - else: - # print("debug 1497") - pass - - - else: - print(timestamp(), "You own more tokens than your MAXTOKENS parameter for ", - token['SYMBOL']) - - if quote > Decimal(token['SELLPRICEINBASE']): - DECIMALS = decimals(inToken) - balance = check_balance(inToken, token['SYMBOL']) - moonbag = int(Decimal(token['MOONBAG']) * DECIMALS) - balance = int(Decimal(balance - moonbag)) - - if balance > 0: - print(timestamp(), "Sell Signal Found " + token['SYMBOL']) - log_price = "{:.18f}".format(quote) - logging.info("Sell Signal Found @" + str(log_price)) - tx = sell(token['SELLAMOUNTINTOKENS'], token['MOONBAG'], inToken, outToken, - token['GAS'], token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], - token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], - token['LIQUIDITYINNATIVETOKEN']) - wait_for_tx(tx, token['ADDRESS'], False) - print( - style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") - sleep(5) - print(style.RESET + "") - else: - pass - - - elif quote > Decimal(token['SELLPRICEINBASE']) and quote != 0: - DECIMALS = decimals(inToken) - balance = check_balance(inToken, token['SYMBOL']) - moonbag = int(Decimal(token['MOONBAG']) * DECIMALS) - balance = int(Decimal(balance - moonbag)) - - if balance > 0: - print(timestamp(), "Sell Signal Found " + token['SYMBOL']) - log_price = "{:.18f}".format(quote) - logging.info("Sell Signal Found @" + str(log_price)) - tx = sell(token['SELLAMOUNTINTOKENS'], token['MOONBAG'], inToken, outToken, token['GAS'], - token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], token["HASFEES"], - token['USECUSTOMBASEPAIR'], token['SYMBOL'], token['LIQUIDITYINNATIVETOKEN']) - wait_for_tx(tx, token['ADDRESS'], False) - print( - style.RESET + "\n --------------------------------------\n" - " √ Tx done. Check your wallet \n" - " --------------------------------------") - sleep(5) - print(style.RESET + "") - - else: - # Double Check For Buy if Sell Signal Triggers - if quote < Decimal(token['BUYPRICEINBASE']): - balance = check_balance(inToken, token['SYMBOL']) - if Web3.fromWei(balance, 'ether') < Decimal(token['MAXTOKENS']): - print(timestamp(), "Buy Signal Found!") - log_price = "{:.18f}".format(quote) - logging.info("Sell Signal Found @" + str(log_price)) - tx = buy(token['BUYAMOUNTINBASE'], outToken, inToken, token['GAS'], - token['SLIPPAGE'], token['GASLIMIT'], token['BOOSTPERCENT'], - token["HASFEES"], token['USECUSTOMBASEPAIR'], token['SYMBOL'], - token['LIQUIDITYINNATIVETOKEN'], token['BUYAFTER_XXX_SECONDS'], - token['MAX_FAILED_TRANSACTIONS_IN_A_ROW']) - wait_for_tx(tx, token['ADDRESS'], False) - else: - print(timestamp(), "Bot has reached MAXTOKENS Position Size for ", token['SYMBOL']) - pass - else: - pass - - sleep(cooldown) - - except Exception as ee: - print(timestamp(), "ERROR. Please go to /log folder and open your error logs : you will find more details.") - logging.exception(ee) - logger1.exception(ee) - sleep(10) - print("Restarting LimitSwap") - logging.info("Restarting LimitSwap") - # Cooldown Logic - timeout = 10 - nonce = 0 - while True: - print(".........Restart Cooldown left " + str(timeout - nonce) + " seconds.............") - nonce += 1 - sleep(1) - if nonce > timeout: - run() - - -try: - - check_logs() - - # Get the user password on first run - userpassword = get_password() - - # Handle any proccessing that is necessary to load the private key for the wallet - parse_wallet_settings(settings, userpassword) - - # The LIMIT balance of the user. - true_balance = auth() - - version = 3.36 - logging.info("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) - print("YOUR BOT IS CURRENTLY RUNNING VERSION " + str(version)) - check_release() - - if true_balance >= 50: - print(timestamp(), "Professional Subscriptions Active") - cooldown = 0.01 - run() - - elif true_balance >= 25 and true_balance < 50: - print(timestamp(), "Trader Subscriptions Active") - cooldown = 3 - run() - elif true_balance >= 10 and true_balance < 25: - print(timestamp(), "Casual Subscriptions Active") - cooldown = 6 - run() - else: - print(timestamp(), - "10 - 50 $LIMIT tokens needed to use this bot, please visit the LimitSwap.com for more info or buy more tokens on Uniswap to use!") - logging.exception( - "10 - 50 $LIMIT tokens needed to use this bot, please visit the LimitSwap.com for more info or buy more tokens on Uniswap to use!") - - -except Exception as e: - print(timestamp(), "ERROR. Please go to /log folder and open your error logs : you will find more details.") - logging.exception(e) - logger1.exception(e) - print("Restarting LimitSwap") - logging.info("Restarting LimitSwap") - # Cooldown Logic - timeout = 10 - nonce = 0 - while True: - print(".........Restart Cooldown left " + str(timeout - nonce) + " seconds.............") - nonce += 1 - sleep(1) - if nonce > timeout: - run() - From 89c366b7ff2cea5ea5e65e90e3ad123297a04729 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:31:23 +0100 Subject: [PATCH 10/16] Update LimitSwap.py --- LimitSwap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LimitSwap.py b/LimitSwap.py index 72b4b67..73eb7ef 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -192,7 +192,7 @@ def load_tokens_file(tokens_path, load_message=True): 'MAXTOKENS': 0, 'MOONBAG': 0, 'SELLAMOUNTINTOKENS': 'all', - 'GAS': 20, + 'GAS': 8, 'BOOSTPERCENT': 50, 'GASLIMIT': 1000000 From 64104bf9afddaf27828c6061c84fdf25dea204a7 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:36:54 +0100 Subject: [PATCH 11/16] Update README.md --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e3b2944..e6d9c9b 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,18 @@ There are 2 ways to install LimitSwap :   -### 1.) Run The Python Code Locally [*this is most ideal and can work on any OS*] +### 1. Run The Python Code Locally [*this is most ideal and can work on any OS*] Here is a tutorial step-by-step: - Download last LimitSwap code here : - Unzip file -- Install Python on your computer : https://www.python.org/downloads/ +- Install Python on your computer : https://www.python.org/downloads/ + +**PLEASE ADD IT TO PATH BY CHECKING THIS OPTION:** + + + - Install Visual Studio : https://visualstudio.microsoft.com/fr/thank-you-downloading-visual-studio/?sku=Community&rel=17 Please install the default package and all those options : @@ -44,7 +49,7 @@ Simply **double-click on "LimitSwap.py"** and it will run, since you've installe     -### 2.) Download the pre-compiled package [*This can lag behind current version*] +### 2. Download the pre-compiled package [*This can lag behind current version*] That we provide on the Release page : it's a .exe file that you can run on your computer. https://github.com/CryptoGnome/LimitSwap/releases From 203ee8bf0cc96e54028c32f4ffa7ffc087580624 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:46:01 +0100 Subject: [PATCH 12/16] Update README.md --- README.md | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6d9c9b..2f573ce 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ LimitSwap is a trading bot for UniSwap & Many Other DEXs. It has the ability to     -## Install LimitSwap -There are 2 ways to install LimitSwap : +## HOW TO INSTALL LimitSwap +There are 3 ways to install LimitSwap :     @@ -33,7 +33,7 @@ Please install the default package and all those options : - Open **Windows Powershell** (or Mac Terminal on MacOs) - Navigate into the unzipped folder -- Run command: "**pip install -r requirements.txt**" --> this will install all the packages needed to run LimitSwap +- Run command: `pip install -r requirements.txt` --> this will install all the packages needed to run LimitSwap ==> And it's done! ✅ @@ -58,6 +58,47 @@ https://github.com/CryptoGnome/LimitSwap/releases 🔴 : it's pre-compiled, so you cannot check the Source Code +  +  + +### 3. With Docker + +#### Requirements +MacOS and Windows users require Docker for Desktop https://www.docker.com/products/docker-desktop +Ubuntu Linux require Docker installed `sudo apt-get install docker.io` + +#### Usage +Navigate into the bot directory and build the Docker image by executing the following command: + +`docker build -t limit_swap_v4 .` + +(For MacOS and Linux) Still within the main directory you can run Docker via: + +`docker run --rm --name limit-swap_v4 -it -v $(pwd)/settings.json:/app/settings.json -v $(pwd)/tokens.json:/app/tokens.json limit_swap_v4` + +(For Windows with Powershell) + +`docker run --rm --name limit-swap_v4 -it -v $PWD/settings.json:/app/settings.json -v $PWD/tokens.json:/app/tokens.json limit_swap_v4` + +If you wish to run the container in the background please include -d for detached. + +The streaming container logs can be visualised with `docker logs -f limit_swap_v4` + +To stop the bot `docker stop limit_swap_v4` + +#### Pros and cons +🟢 : easy to setup if you know Docker + +🔴 : needs Docker + +  + +  + +  + +  + ## Developers 🔧 Want to help contribute to LimitSwap, reach out on telegram all you need to do is make changes or fix bugs and we will pay developer bounties in $LIMIT for helping make the bot batter! From 967dd1d32c445517488639d16d8d23559ef67559 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:47:31 +0100 Subject: [PATCH 13/16] Update settings.json --- settings.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/settings.json b/settings.json index b1cd58c..cef0366 100644 --- a/settings.json +++ b/settings.json @@ -1,10 +1,10 @@ [ { - "LIMITWALLETPRIVATEKEY": "private key to wallet that hold LIMIT goes here - see secuirity tips on wiki!!!", - "LIMITWALLETADDRESS": "wallet the holds LIMIT", - "WALLETADDRESS": "wallet address you want to trade on", - "PRIVATEKEY": "private key to trading wallet here - see secuirity tips on wiki!!!", - "USECUSTOMNODE": "false", + "LIMITWALLETPRIVATEKEY": "do not enter it manually, open the bot : it will encrypt it", + "LIMITWALLETADDRESS": "wallet address where you hold your LIMIT tokens", + "WALLETADDRESS": "wallet address you want to trade on : can be different from LIMIT wallet", + "PRIVATEKEY": "do not enter it manually, open the bot : it will encrypt it", + "USECUSTOMNODE": "false", "CUSTOMNODE": "put your own node here if you want and make, USECUSTOMNODE = TRUE", "EXCHANGE": "pancakeswap", "EXCHANGEVERSION": "2", From 179bf002d6a15b418243e2008d5b8836efa2df38 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 23:14:35 +0100 Subject: [PATCH 14/16] Update README.md --- README.md | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2f573ce..d44b5e4 100644 --- a/README.md +++ b/README.md @@ -16,28 +16,48 @@ There are 3 ways to install LimitSwap : ### 1. Run The Python Code Locally [*this is most ideal and can work on any OS*] Here is a tutorial step-by-step: -- Download last LimitSwap code here : +- [x] Download last LimitSwap code here : -- Unzip file -- Install Python on your computer : https://www.python.org/downloads/ +- [x] Unzip file +- [x] Install Python on your computer : https://www.python.org/downloads/ **PLEASE ADD IT TO PATH BY CHECKING THIS OPTION:** -- Install Visual Studio : https://visualstudio.microsoft.com/fr/thank-you-downloading-visual-studio/?sku=Community&rel=17 +- [x] Install Visual Studio : https://visualstudio.microsoft.com/fr/thank-you-downloading-visual-studio/?sku=Community&rel=17 Please install the default package and all those options : ![image](https://user-images.githubusercontent.com/70858574/145580447-bd648d6d-c3ce-4dd9-8527-84ecfb5f30cc.png) -- Open **Windows Powershell** (or Mac Terminal on MacOs) -- Navigate into the unzipped folder -- Run command: `pip install -r requirements.txt` --> this will install all the packages needed to run LimitSwap +- [x] Open **Windows Powershell** (or Mac Terminal on MacOs) -==> And it's done! ✅ +- [X] Run this command to locate LimitSwap folder : -Simply **double-click on "LimitSwap.py"** and it will run, since you've installed Python 👍👍 +`Get-ChildItem -Filter LimitSwap.py -Recurse -ErrorAction SilentlyContinue -Force` + +- [X] Copy the Directory + +(example : `C:\Users\Administrator\Desktop\LimitSwap-master`) + +- [X] Paste the Directory after the "cd" command to navigate through the bot folder + +(example : ` cd C:\Users\Administrator\Desktop\LimitSwap-master`) + +- [x] It should look like this: + + + +- [x] Run command: `pip install -r requirements.txt` --> this will install all the packages needed to run LimitSwap + +  + +✅ ✅ ✅ And it's done! ✅ ✅ ✅ + +  + +- [x] Simply **double-click on "LimitSwap.py"** and it will run, since you've installed Python 👍👍   @@ -97,8 +117,6 @@ To stop the bot `docker stop limit_swap_v4`   -  - ## Developers 🔧 Want to help contribute to LimitSwap, reach out on telegram all you need to do is make changes or fix bugs and we will pay developer bounties in $LIMIT for helping make the bot batter! From 5e7341ae87a5d070071c1cb3315b04265d69ef59 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sat, 11 Dec 2021 23:51:26 +0100 Subject: [PATCH 15/16] Update LimitSwap.py --- LimitSwap.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 73eb7ef..3fda5f3 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -972,9 +972,23 @@ def check_pool(inToken, outToken, symbol): DECIMALS = decimals(outToken) pair_contract = client.eth.contract(address=pair_address, abi=lpAbi) reserves = pair_contract.functions.getReserves().call() - pooled = reserves[1] / DECIMALS - # print("Debug LIQUIDITYAMOUNT line 627 :", pooled, "in token:", outToken) + # This is a little trick to improve reliability of LIQUIDITYCHECK, before we're able to solve this bug completely + # We check if reserves[1] is a "regular number", otherwise we use reserves[0]. No better idea for now. + # print("----------------------------------------------------------------------") + if 0.01 <= (int(reserves[1]) / DECIMALS) <= 10000000: + pooled = reserves[1] / DECIMALS + # print("on choisit reserves[1]") + else: + pooled = reserves[0] / DECIMALS + # print("on choisit reserves[0]") + # print("----------------------------------------------------------------------") + # print("Debug reserves[0] line 982: ", reserves[0] / DECIMALS) + # print("Debug reserves[1] line 982: ", reserves[1] / DECIMALS) + # print("----------------------------------------------------------------------") + # print("Debug LIQUIDITYAMOUNT line 981 :", pooled, "in token:", outToken) + # print("----------------------------------------------------------------------") + # sleep(50) return pooled From 80117706604fddec7244d63b0579253bac56fc24 Mon Sep 17 00:00:00 2001 From: TsarBuig <70858574+tsarbuig@users.noreply.github.com> Date: Sun, 12 Dec 2021 11:54:55 +0100 Subject: [PATCH 16/16] Update LimitSwap.py --- LimitSwap.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/LimitSwap.py b/LimitSwap.py index 3fda5f3..4d3bd65 100755 --- a/LimitSwap.py +++ b/LimitSwap.py @@ -973,22 +973,26 @@ def check_pool(inToken, outToken, symbol): pair_contract = client.eth.contract(address=pair_address, abi=lpAbi) reserves = pair_contract.functions.getReserves().call() - # This is a little trick to improve reliability of LIQUIDITYCHECK, before we're able to solve this bug completely - # We check if reserves[1] is a "regular number", otherwise we use reserves[0]. No better idea for now. - # print("----------------------------------------------------------------------") - if 0.01 <= (int(reserves[1]) / DECIMALS) <= 10000000: - pooled = reserves[1] / DECIMALS - # print("on choisit reserves[1]") - else: + # Tokens are ordered by the token contract address + # The token contract address can be interpreted as a number + # And the smallest one will be token0 internally + + ctnb1 = int(inToken, 16) + ctnb2 = int(outToken, 16) + + if (ctnb1 > ctnb2): + # print("reserves[0] is for outToken:") pooled = reserves[0] / DECIMALS - # print("on choisit reserves[0]") + else: + # print("reserves[0] is for inToken:") + pooled = reserves[1] / DECIMALS + # print("----------------------------------------------------------------------") # print("Debug reserves[0] line 982: ", reserves[0] / DECIMALS) # print("Debug reserves[1] line 982: ", reserves[1] / DECIMALS) # print("----------------------------------------------------------------------") # print("Debug LIQUIDITYAMOUNT line 981 :", pooled, "in token:", outToken) # print("----------------------------------------------------------------------") - # sleep(50) return pooled