diff --git a/LimitSwap.py b/LimitSwap.py index ab783fe..4d3bd65 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 @@ -16,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. # @@ -31,6 +32,10 @@ # 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' @@ -44,27 +49,36 @@ 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") +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 # ---------------------------- @@ -72,7 +86,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 @@ -80,9 +95,10 @@ def printt_v(*print_args): # 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))) + print(timestamp(), ' '.join(map(str, print_args))) + def printt_err(*print_args): # Function: printt_err @@ -91,9 +107,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 @@ -102,24 +119,24 @@ def load_settings_file(settings_path, load_message = True): # 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.") + 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() @@ -127,14 +144,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 @@ -146,7 +164,7 @@ def load_tokens_file(tokens_path, load_message = True): 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() @@ -156,32 +174,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': 8, + '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() @@ -393,7 +413,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'] @@ -577,7 +597,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 +608,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,7 +620,7 @@ 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 @@ -616,18 +636,18 @@ def get_password(): 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 +672,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) @@ -663,17 +686,17 @@ 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'], 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.") + # 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 @@ -693,7 +716,7 @@ def parse_wallet_settings(settings, pwd): # Accepts user input for new private keys and wallet addresses # # returns: none (exits on incorrect password) - + settings_changed = False # Check for limit wallet information @@ -714,10 +737,10 @@ def parse_wallet_settings(settings, pwd): 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,7 +754,7 @@ 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) @@ -739,8 +762,6 @@ def parse_wallet_settings(settings, pwd): save_settings(settings, pwd) - - def decimals(address): try: balanceContract = client.eth.contract(address=Web3.toChecksumAddress(address), abi=standardAbi) @@ -852,8 +873,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,9 +898,9 @@ 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.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() @@ -890,17 +910,26 @@ 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: + 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) + print(style.YELLOW + "\n ---------------------------------------------------------------------------\n" + " You need to APPROVE this token before selling it : LimitSwap will do it now\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" + " ---------------------------------------------------------") + print(style.RESET + "\n") return @@ -943,13 +972,31 @@ 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) + # 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 + 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("----------------------------------------------------------------------") 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 +1012,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) + 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 +1068,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 +1100,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 +1121,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 +1148,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 +1157,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 +1191,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 +1227,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 +1238,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 +1269,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 +1402,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 +1429,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 +1447,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 +1458,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 +1490,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 +1506,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 +1543,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 +1630,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 +1647,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 +1667,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 +1758,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,7 +1845,6 @@ def sell(amount, moonbag, inToken, outToken, gas, slippage, gaslimit, boost, fee def run(): - global failedtransactionsamount try: @@ -1600,8 +1856,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" + 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 +1868,15 @@ def run(): 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': @@ -1632,11 +1890,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,17 +1903,17 @@ def run(): 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']) @@ -1668,7 +1926,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 +1955,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 +1973,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 +2005,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 +2022,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: @@ -1781,8 +2046,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) @@ -1799,6 +2064,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 +2088,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 +2106,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']) @@ -1909,6 +2188,3 @@ def run(): sleep(1) if nonce > timeout: run() - - - diff --git a/README.md b/README.md index e3b2944..d44b5e4 100644 --- a/README.md +++ b/README.md @@ -7,32 +7,57 @@ 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 :     -### 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 : +- [x] Download last LimitSwap code here : -- Unzip file -- Install Python on your computer : https://www.python.org/downloads/ -- Install Visual Studio : https://visualstudio.microsoft.com/fr/thank-you-downloading-visual-studio/?sku=Community&rel=17 +- [x] Unzip file +- [x] Install Python on your computer : https://www.python.org/downloads/ + +**PLEASE ADD IT TO PATH BY CHECKING THIS OPTION:** + + + +- [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) + +- [X] Run this command to locate LimitSwap folder : + +`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: -==> And it's done! ✅ + -Simply **double-click on "LimitSwap.py"** and it will run, since you've installed Python 👍👍 +- [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 👍👍   @@ -44,7 +69,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 @@ -53,6 +78,45 @@ 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! 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",