Building a Sandwich Trading Bot with Python for Uniswap and MetaMask: A Step-by-Step Tutorial — Rami Jaloudi

Rami Jaloudi
5 min readJun 14, 2023

--

Trading bots have become increasingly popular in the cryptocurrency world. In this tutorial, we will walk you through the process of building a sandwich trading bot using the Uniswap decentralized exchange protocol and interacting with it using the MetaMask wallet. This bot aims to capitalize on price swings between two assets by placing buy and sell orders at predefined price levels. By following this step-by-step guide, you’ll learn how to integrate Uniswap, fetch real-time market prices, execute trades, and ensure secure interactions using MetaMask.

Prerequisites:

  1. Basic understanding of Python programming language.
  2. Familiarity with the Uniswap protocol and MetaMask wallet.
  3. Basic knowledge of decentralized exchanges and trading strategies.

Step 1: Setting Up the Development Environment

  • Install Python and necessary libraries: Web3.py, requests, eth-account.
  • Create a new Python script for our sandwich trading bot.

Step 2: Initialize the Web3 Provider and Load the Wallet

  • Obtain an Infura project ID and set it as the provider URL.
  • Initialize Web3 with the provider URL and enable the geth_poa_middleware.
  • Load the MetaMask wallet by providing the private key and passphrase.

Step 3: Configure the Uniswap Contract Addresses

  • Obtain the router contract address from the Uniswap documentation.
  • Set the addresses of the tokens you want to trade.

Step 4: Fetch Real-Time Token Prices

  • Use the CoinGecko API to fetch the market prices of the tokens.
  • You will need a CoinGeck API Key, which can be retrieved here: https://www.coingecko.com/en/api/pricing. Get 20% off any CoinGecko API plan by applying RAMIJALOUDI20 at checkout.
  • Implement a function to retrieve the token prices using the API.

Step 5: Execute the Sandwich Trading Strategy

  • Calculate the target buy and sell prices based on the price differences.
  • Simulate checking the market prices or implement your own logic.
  • Execute the buy trade if the conditions are met.
  • Execute the sell trade if the conditions are met.

Step 6: Interact with Uniswap and Execute Trades

  • Approve the token transfer using the router contract’s approve function.
  • Build the transaction to swap tokens using the swapExactTokensForTokens function.
  • Sign and send the transaction to the Ethereum network.
  • Wait for the transaction receipt and handle any errors.

Step 7: Testing and Running the Sandwich Trading Bot

  • Set up a testing environment or use a sandbox on the Ethereum network.
  • Modify the code to suit your specific trading requirements.
  • Run the sandwich trading bot script and observe the execution of trades.

To make the sandwich trading bot work with Uniswap and MetaMask, you’ll need to integrate the Uniswap protocol and interact with it using the MetaMask wallet. Here’s an version of the sandwich trading bot that incorporates these components:

import time
import json
import requests
from web3 import Web3
from web3.middleware import geth_poa_middleware
from web3.exceptions import InvalidAddress
from eth_account import Account
# Ethereum node provider URL
provider_url = 'https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'
# Uniswap contract addresses
router_address = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'
token_1_address = '0xTOKEN_1_ADDRESS' # Example token 1 address
token_2_address = '0xTOKEN_2_ADDRESS' # Example token 2 address
# MetaMask wallet private key and passphrase
wallet_private_key = 'YOUR_WALLET_PRIVATE_KEY'
wallet_passphrase = 'YOUR_WALLET_PASSPHRASE'
# Initialize Web3 provider
web3 = Web3(Web3.HTTPProvider(provider_url))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)
# Load the wallet
wallet = Account.from_key(wallet_private_key)
# Set the contract addresses
router_contract = web3.eth.contract(address=Web3.toChecksumAddress(router_address), abi=json.loads(UNISWAP_ROUTER_ABI))
# Specify the token and trade amounts
token_1_amount = web3.toWei(1, 'ether') # Amount of token 1 to trade
token_2_amount = web3.toWei(1, 'ether') # Amount of token 2 to trade
trade_slippage = 0.05 # Slippage tolerance (5%)
# Function to execute the trade
def execute_sandwich_trade():
# Get the latest token prices from Uniswap
token_1_price = get_token_price(token_1_address)
token_2_price = get_token_price(token_2_address)
# Calculate the target prices
buy_price = token_1_price - (token_2_price * (1 + trade_slippage))
sell_price = token_1_price + (token_2_price * (1 - trade_slippage))
# Simulate checking the market prices
# Replace this with your own logic to fetch real-time market prices
token_1_market_price = get_token_price(token_1_address)
token_2_market_price = get_token_price(token_2_address)
# Execute buy trade
if token_1_market_price <= buy_price:
print("Executing buy trade…")
execute_uniswap_trade(token_2_address, token_2_amount, token_1_address, token_1_amount)
# Execute sell trade
elif token_1_market_price >= sell_price:
print("Executing sell trade…")
execute_uniswap_trade(token_1_address, token_1_amount, token_2_address, token_2_amount)
# Function to get the token price from Uniswap
def get_token_price(token_address):
try:
response = requests.get(f'https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses={token_address}&vs_currencies=usd')
data = response.json()
token_price = data[token_address.lower()]['usd']
return token_price
except Exception as e:
print(f"Error fetching token price: {e}")
return None
# Function to execute the trade on Uniswap
def execute_uniswap_trade(from_token, from_amount, to_token, to_amount):
try:
# Approve the token transfer
approve_tx = router_contract.functions.approve(
Web3.toChecksumAddress(router_address),
from_amount
).buildTransaction({
'from': wallet.address,
'gas': 100000,
'gasPrice': web3.toWei('5', 'gwei'),
'nonce': web3.eth.getTransactionCount(wallet.address),
})
signed_approve_tx = web3.eth.account.sign_transaction(approve_tx, private_key=wallet.privateKey)
approve_tx_hash = web3.eth.send_raw_transaction(signed_approve_tx.rawTransaction)
web3.eth.wait_for_transaction_receipt(approve_tx_hash)
# Execute the swap
swap_tx = router_contract.functions.swapExactTokensForTokens(
from_amount,
to_amount,
[from_token, to_token],
wallet.address,
int(time.time()) + 10000
).buildTransaction({
'from': wallet.address,
'gas': 200000,
'gasPrice': web3.toWei('5', 'gwei'),
'nonce': web3.eth.getTransactionCount(wallet.address),
})
signed_swap_tx = web3.eth.account.sign_transaction(swap_tx, private_key=wallet.privateKey)
swap_tx_hash = web3.eth.send_raw_transaction(signed_swap_tx.rawTransaction)
web3.eth.wait_for_transaction_receipt(swap_tx_hash)
print("Trade executed successfully.")
except InvalidAddress as e:
print(f"Invalid contract address: {e}")
except Exception as e:
print(f"Error executing trade: {e}")
# Main loop
while True:
execute_sandwich_trade()
time.sleep(10) # Wait for 10 seconds before executing the next trade

In this code, we have added the ability to fetch token prices using the CoinGecko API and execute trades on Uniswap using the MetaMask wallet. You’ll need to replace 'YOUR_INFURA_PROJECT_ID', 'YOUR_WALLET_PRIVATE_KEY', 'YOUR_WALLET_PASSPHRASE', '0xTOKEN_1_ADDRESS', '0xTOKEN_2_ADDRESS', and 'UNISWAP_ROUTER_ABI' with your own values.

Make sure you have the necessary dependencies installed, including the Web3.py, requests, and eth-account libraries. Additionally, replace the get_token_price() function with your own logic to fetch real-time market prices.

Please note that trading bots involve risks, and it’s crucial to thoroughly test and validate your strategy before deploying it with real funds. Ensure that you understand the risks associated with trading strategies, smart contract interactions, and the security considerations of using a wallet like MetaMask.

Remember to handle gas fees appropriately and conduct thorough research or consult with a financial advisor to make informed trading decisions.

Conclusion: In this tutorial, we have covered the step-by-step process of building a sandwich trading bot that works with the Uniswap decentralized exchange protocol and MetaMask wallet. We explored key concepts such as initializing the development environment, fetching real-time token prices, executing trades on Uniswap, and ensuring secure interactions using MetaMask. By following this guide, you can gain hands-on experience in developing and deploying your own trading bot, allowing you to explore and implement various trading strategies within the decentralized finance ecosystem.

Remember, trading bots come with inherent risks, and it’s crucial to thoroughly test and validate your strategy before deploying it with real funds. Additionally, stay informed about market trends, risk management techniques, and security considerations to make informed trading decisions. Happy bot building and happy trading!

Below is a supplementary Arbitrage Cryptocurrency Trading Bot you can use on Uniswap and another DEX where there are price difference you can profit on:

import requests
import time

class ArbitrageBot:
def __init__(self, exchange1_api_url, exchange2_api_url):
self.exchange1_api_url = exchange1_api_url
self.exchange2_api_url = exchange2_api_url

def fetch_price(self, exchange_api_url):
response = requests.get(exchange_api_url)
data = response.json()
return float(data["price"])

def execute_trade(self, exchange_api_url, trade_data):
response = requests.post(exchange_api_url, json=trade_data)
return response.json()

def find_arbitrage_opportunity(self):
price1 = self.fetch_price(self.exchange1_api_url)
price2 = self.fetch_price(self.exchange2_api_url)

# Calculate potential profit percentage
profit_percentage = (price2 - price1) / price1 * 100

if profit_percentage > 0:
# Perform arbitrage trade
trade_data = {
# Define trade parameters for buying on exchange 1 and selling on exchange 2
}
trade_result = self.execute_trade(self.exchange1_api_url, trade_data)
print("Arbitrage opportunity found:")
print(f"Buy on Exchange 1, Sell on Exchange 2")
print(f"Profit Percentage: {profit_percentage}%")
print(f"Trade Result: {trade_result}")
else:
print("No arbitrage opportunity found.")

def run(self, interval_seconds):
while True:
self.find_arbitrage_opportunity()
time.sleep(interval_seconds)

# Example usage
if __name__ == "__main__":
exchange1_api_url = "https://exchange1.com/api"
exchange2_api_url = "https://exchange2.com/api"

bot = ArbitrageBot(exchange1_api_url, exchange2_api_url)
bot.run(interval_seconds=10)

--

--

Rami Jaloudi
Rami Jaloudi

Written by Rami Jaloudi

I'm a Tech Enthusiast, including Computer Science, Data Analytics, eDiscovery, Data Mining & Blockchain. I write about things that interest me.