├── README.md ├── constants.py ├── main.py ├── wallets.py └── washbot.py /README.md: -------------------------------------------------------------------------------- 1 | # Uniswap V3 Bot 2 | ![import_random](https://user-images.githubusercontent.com/60722582/188267322-1774041b-8018-4f6f-8f6e-2528b6f47ee6.jpeg) 3 | 4 | ## Intro 5 | 6 | * Uses https://github.com/uniswap-python to wash trade a token on Uniswap. 7 | * *Randomly* does a trade every **1-3600 seconds**. 8 | * *Randomly* chooses to swap `token0` for `token1` or vice versa. 9 | * *Randomly* chooses to swap **1%-10%** of token balance. 10 | * Goal is to randomly wash trade within a Uniswap token pair to pump up volume. 11 | 12 | ## How To 13 | 14 | * `wallets.py` is where you put your **wallet addresses** & **private keys**. 15 | * `constants.py` is where the **RPC Endpoint URLs** and **ERC20 Token Info** are stored. 16 | * `washbot.py` contains `class WashBot()`. You can configure it. 17 | * `main.py` is where you initialize your bots. You can deploy as many as you want and set different logics. 18 | 19 | ## Feeding the Bots 20 | 21 | * Once deployed, the bots will keep wash trading forever, until you halt them that is. 22 | * Due to **Maker Fee** & **Gas**, the bots will consume **tokens** and **gas** over time. 23 | * Send **tokens** and **gas** to the bots' wallet addresses to refuel them. -------------------------------------------------------------------------------- /constants.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | 3 | # RPC endpoints 4 | RPC = { 5 | # Found on https://ethereumnodes.com/ 6 | 'mainnet': 'https://cloudflare-eth.com/', 7 | # Found on https://www.allthatnode.com/polygon.dsrv 8 | 'polygon': 'https://polygon-mainnet-rpc.allthatnode.com:8545', 9 | # Found on https://umbria.network/connect/ethereum-testnet-g%C3%B6rli 10 | 'goerli': 'https://rpc.goerli.mudit.blog/' 11 | } 12 | 13 | 14 | # ERC20 token info 15 | WETH = { 16 | 'mainnet': { 17 | 'symbol': 'WETH', 18 | 'address': Web3.toChecksumAddress( 19 | '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' 20 | ), 21 | 'decimals': 18 22 | }, 23 | 'polygon': { 24 | 'symbol': 'WETH', 25 | 'address': Web3.toChecksumAddress( 26 | '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' 27 | ), 28 | 'decimals': 18 29 | } 30 | } 31 | 32 | WBTC = { 33 | 'mainnet': { 34 | 'symbol': 'WBTC', 35 | 'address' : Web3.toChecksumAddress( 36 | '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599' 37 | ), 38 | 'decimals': 8 39 | }, 40 | 'polygon': { 41 | 'symbol': 'WBTC', 42 | 'address' : Web3.toChecksumAddress( 43 | '0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6' 44 | ), 45 | 'decimals': 8 46 | } 47 | } 48 | 49 | USDC = { 50 | 'mainnet': { 51 | 'symbol': 'USDC', 52 | 'address' : Web3.toChecksumAddress( 53 | '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' 54 | ), 55 | 'decimals': 6 56 | }, 57 | 'polygon': { 58 | 'symbol': 'USDC', 59 | 'address' : Web3.toChecksumAddress( 60 | '0x2791bca1f2de4661ed88a30c99a7a9449aa84174' 61 | ), 62 | 'decimals': 6 63 | } 64 | } 65 | 66 | USDT = { 67 | 'mainnet': { 68 | 'symbol': 'USDT', 69 | 'address' : Web3.toChecksumAddress( 70 | '0xdAC17F958D2ee523a2206206994597C13D831ec7' 71 | ), 72 | 'decimals': 6 73 | }, 74 | 'polygon': { 75 | 'symbol': 'USDT', 76 | 'address' : Web3.toChecksumAddress( 77 | '0xc2132d05d31c914a87c6611c10748aeb04b58e8f' 78 | ), 79 | 'decimals': 6 80 | } 81 | } 82 | 83 | DAI = { 84 | 'mainnet': { 85 | 'symbol': 'DAI', 86 | 'address' : Web3.toChecksumAddress( 87 | '0x6b175474e89094c44da98b954eedeac495271d0f' 88 | ), 89 | 'decimals': 18 90 | }, 91 | 'polygon': { 92 | 'symbol': 'DAI', 93 | 'address' : Web3.toChecksumAddress( 94 | '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063' 95 | ), 96 | 'decimals': 18 97 | } 98 | } 99 | 100 | WMATIC = { 101 | 'polygon': { 102 | 'symbol': 'WMATIC', 103 | 'address' : Web3.toChecksumAddress( 104 | '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270' 105 | ), 106 | 'decimals': 18 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Uniswap wash trade bot by LaDoger 2 | 3 | import time 4 | import random 5 | import constants as c # From constants.py file 6 | from wallets import WALLETS # From wallets.py file 7 | from washbot import WashBot # From washbot.py file 8 | 9 | 10 | def main(): 11 | """Use WashBot to randomly do trades on Uniswap.""" 12 | 13 | # Can deploy as many bots here 14 | bot0a = WashBot( 15 | address=WALLETS[0]['address'], # Bot wallet address. 16 | private_key=WALLETS[0]['private_key'], # Private key of bot wallet. 17 | uniswap_version=3, # Choose Uniswap version 18 | network='polygon', # Choose network 19 | token0=c.WETH, # Choose token0 20 | token1=c.USDT, # Choose token1 21 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 22 | ) 23 | 24 | bot0b = WashBot( 25 | address=WALLETS[0]['address'], # Bot wallet address. 26 | private_key=WALLETS[0]['private_key'], # Private key of bot wallet. 27 | uniswap_version=3, # Choose Uniswap version 28 | network='polygon', # Choose network 29 | token0=c.WBTC, # Choose token0 30 | token1=c.DAI, # Choose token1 31 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 32 | ) 33 | 34 | bot1a = WashBot( 35 | address=WALLETS[1]['address'], # Bot wallet address. 36 | private_key=WALLETS[1]['private_key'], # Private key of bot wallet. 37 | uniswap_version=3, # Choose Uniswap version 38 | network='polygon', # Choose network 39 | token0=c.WETH, # Choose token0 40 | token1=c.USDT, # Choose token1 41 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 42 | ) 43 | 44 | bot1b = WashBot( 45 | address=WALLETS[1]['address'], # Bot wallet address. 46 | private_key=WALLETS[1]['private_key'], # Private key of bot wallet. 47 | uniswap_version=3, # Choose Uniswap version 48 | network='polygon', # Choose network 49 | token0=c.WBTC, # Choose token0 50 | token1=c.DAI, # Choose token1 51 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 52 | ) 53 | 54 | bot2a = WashBot( 55 | address=WALLETS[2]['address'], # Bot wallet address. 56 | private_key=WALLETS[2]['private_key'], # Private key of bot wallet. 57 | uniswap_version=3, # Choose Uniswap version 58 | network='polygon', # Choose network 59 | token0=c.WETH, # Choose token0 60 | token1=c.USDT, # Choose token1 61 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 62 | ) 63 | 64 | bot2b = WashBot( 65 | address=WALLETS[2]['address'], # Bot wallet address. 66 | private_key=WALLETS[2]['private_key'], # Private key of bot wallet. 67 | uniswap_version=3, # Choose Uniswap version 68 | network='polygon', # Choose network 69 | token0=c.WBTC, # Choose token0 70 | token1=c.DAI, # Choose token1 71 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 72 | ) 73 | 74 | bot3a = WashBot( 75 | address=WALLETS[3]['address'], # Bot wallet address. 76 | private_key=WALLETS[3]['private_key'], # Private key of bot wallet. 77 | uniswap_version=3, # Choose Uniswap version 78 | network='polygon', # Choose network 79 | token0=c.WETH, # Choose token0 80 | token1=c.USDT, # Choose token1 81 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 82 | ) 83 | 84 | bot3b = WashBot( 85 | address=WALLETS[3]['address'], # Bot wallet address. 86 | private_key=WALLETS[3]['private_key'], # Private key of bot wallet. 87 | uniswap_version=3, # Choose Uniswap version 88 | network='polygon', # Choose network 89 | token0=c.WBTC, # Choose token0 90 | token1=c.DAI, # Choose token1 91 | fee=None # Choose fee (fee=3000 means 0.3% maker fee) 92 | ) 93 | 94 | # Create a list of bots you want to trade with 95 | bots = [bot0a, bot0b, bot1a, bot1b, bot2a, bot2b, bot3a, bot3b] 96 | 97 | # Loop after each trade attempt 98 | while True: 99 | try: 100 | # Randomly choose a bot from bot_list 101 | random_bot = random.choice(bots) 102 | 103 | random_bot.buy_or_sell() # The main thing!!! 104 | 105 | # You can add complex trading logic here 106 | 107 | 108 | # Decide how many seconds to rest the bot 109 | rest = int(random.randrange(1, 42) ** 2) # 1-1764 seconds 110 | print(f'Bot resting for {rest} seconds...\n') 111 | time.sleep(rest) 112 | 113 | except: 114 | print('Error! Will try again in 10 seconds...\n') 115 | time.sleep(10) # Wait 10 seconds then try again 116 | 117 | 118 | if __name__ == '__main__': 119 | main() 120 | -------------------------------------------------------------------------------- /wallets.py: -------------------------------------------------------------------------------- 1 | # Wallets for the bots to trade with 2 | # A tuple of dicts 3 | WALLETS = ( 4 | { 5 | 'address': '0x...', # address0 6 | 'private_key': '***' # key0 7 | }, 8 | { 9 | 'address': '0x...', # address1 10 | 'private_key': '***' # key1 11 | }, 12 | { 13 | 'address': '0x...', # address2 14 | 'private_key': '***' # key2 15 | }, 16 | { 17 | 'address': '0x...', # address3 18 | 'private_key': '***' # key3 19 | } 20 | ) 21 | -------------------------------------------------------------------------------- /washbot.py: -------------------------------------------------------------------------------- 1 | # Uniswap wash trade bot by LaDoger 2 | 3 | import web3 4 | import random 5 | import constants as c # From constants.py file 6 | from uniswap import Uniswap # Library from https://uniswap-python.com/ 7 | 8 | # To solve a weird error 9 | # https://stackoverflow.com/questions/70812529/the-field-extradata-is-97-bytes-but-should-be-32-it-is-quite-likely-that-you-a 10 | from web3.middleware import geth_poa_middleware 11 | 12 | 13 | class WashBot(): 14 | """A bot that randomly trades on Uniswap.""" 15 | 16 | # Decide which wallet & token pair to trade. 17 | def __init__(self, 18 | address, 19 | private_key, 20 | uniswap_version, 21 | network, 22 | token0, 23 | token1, 24 | fee=None 25 | ): 26 | self.address = address 27 | self.private_key = private_key 28 | self.version = uniswap_version 29 | self.network = network 30 | self.token0 = token0[network] 31 | self.token1 = token1[network] 32 | self.fee = fee 33 | 34 | # To solve the weird error mentioned above 35 | self.w3 = web3.Web3(web3.HTTPProvider(c.RPC[network])) 36 | self.w3.middleware_onion.inject(geth_poa_middleware, layer=0) 37 | 38 | self.uniswap = Uniswap( 39 | address=address, # Bot wallet address 40 | private_key=private_key, # Bot wallet private key 41 | version=uniswap_version, # Uniswap Version 42 | provider=c.RPC[network], # RPC provider endpoint url 43 | web3=self.w3 # To solve error https://github.com/uniswap-python/uniswap-python/issues/216 44 | ) 45 | 46 | 47 | def swap_token0_for_token1(self): 48 | """Swap 1%-10% of token0 for token1.""" 49 | 50 | qty = self.uniswap.get_token_balance( 51 | self.token0['address'] 52 | ) / 10 ** self.token0['decimals'] 53 | print(f'Wallet Address: {self.address}') 54 | print(f'Balance of {self.token0["symbol"]}: {qty}') 55 | 56 | # Choose from 1% to 10.24% to swap 57 | portion = random.randrange(10, 32) ** 2 / 100 58 | print(f'Swapping {portion}% of {self.token0["symbol"]} balance...') 59 | portion = portion / 100 60 | 61 | amount = int(qty * 10 ** self.token0['decimals'] * portion) 62 | 63 | self.uniswap.make_trade( 64 | self.token0['address'], 65 | self.token1['address'], 66 | amount, 67 | recipient=None, 68 | fee=self.fee, 69 | slippage=None, 70 | fee_on_transfer=False # Uniswap V3 doesn't support fee_on_transfer 71 | ) 72 | 73 | print(f'Swapped {amount / 10 ** self.token0["decimals"]} {self.token0["symbol"]} for {self.token1["symbol"]}.') 74 | 75 | 76 | def swap_token1_for_token0(self): 77 | """Swap 1%-10% of token1 for token0.""" 78 | 79 | qty = self.uniswap.get_token_balance( 80 | self.token1['address'] 81 | ) / 10 ** self.token1['decimals'] 82 | print(f'Wallet Address: {self.address}') 83 | print(f'Balance of {self.token1["symbol"]}: {qty}') 84 | 85 | # Choose from 1% to 10.24% to swap 86 | portion = random.randrange(10, 32) ** 2 / 100 87 | print(f'Swapping {portion}% of {self.token1["symbol"]} balance...') 88 | portion = portion / 100 89 | 90 | amount = int(qty * 10 ** self.token1['decimals'] * portion) 91 | 92 | self.uniswap.make_trade( 93 | self.token1['address'], 94 | self.token0['address'], 95 | amount, 96 | recipient=None, 97 | fee=self.fee, 98 | slippage=None, 99 | fee_on_transfer=False # Uniswap V3 doesn't support fee_on_transfer 100 | ) 101 | 102 | print(f'Swapped {amount / 10 ** self.token1["decimals"]} {self.token1["symbol"]} for {self.token0["symbol"]}.') 103 | 104 | 105 | def buy_or_sell(self): 106 | """Randomly choose to swap what for what.""" 107 | 108 | print('Bot contemplating...') 109 | r = random.choice(['0for1', '1for0']) 110 | 111 | if r == '0for1': 112 | self.swap_token0_for_token1() 113 | else: 114 | self.swap_token1_for_token0() 115 | --------------------------------------------------------------------------------