MavrickBot: Building a Sandwich Trading Bot on Ethereum (Part 1)

Jane Karaks
4 min readAug 3, 2024

--

In the fast-paced world of decentralized finance (DeFi), opportunities for profit can appear and disappear in the blink of an eye. As a developer and crypto enthusiast, I’ve always been fascinated by the intricate dance of trades that occurs on decentralized exchanges (DEXs) like Uniswap. This fascination led me to embark on an exciting journey: creating a sandwich trading bot that could capitalize on these fleeting moments of arbitrage.

Mavrick Bot Cover

In this article, I’ll walk you through the conception and development of MavrickBot, a smart contract designed to execute sandwich trades on Uniswap V3. We’ll explore the ideas behind the bot, the challenges faced during development, and dive into the key components of the contract.

Github: https://github.com/JaneKaraks/MavrickCryptoBot

Youtube: https://www.youtube.com/watch?v=V3GQm1SFYpA&t=27s

The Genesis of MavrickBot

The idea for MavrickBot came from observing the intricate workings of DEXs and noticing how certain traders were able to profit from large trades by “sandwiching” them with their own transactions. I realized that with the right code, this process could be automated, potentially creating a steady stream of profits.

The core concept is simple:

  1. Detect a large pending trade on Uniswap V3
  2. Quickly buy the target token before the large trade executes
  3. Sell the token immediately after the large trade, profiting from the price increase

However, implementing this concept securely and efficiently on the Ethereum blockchain presented several challenges.

Challenges in Development

1. Speed and Gas Optimization

One of the biggest challenges was ensuring the bot could act quickly enough to execute trades before market conditions changed. This required careful optimization of the contract’s functions and consideration of gas costs.

2. Security and Risk Management

Given that the bot would be handling potentially large amounts of cryptocurrency, security was paramount. I needed to implement robust access controls, safeguards against reentrancy attacks, and mechanisms to limit potential losses.

3. Flexibility and Configurability

Market conditions and trading strategies can change rapidly in DeFi. I wanted to create a bot that could be easily adjusted and fine-tuned without needing to deploy a new contract each time.

4. Interfacing with Uniswap V3

Uniswap V3 introduced new complexities with its concentrated liquidity model. Ensuring the bot could correctly interact with Uniswap V3 pools and accurately estimate trade outcomes was crucial.

Key Components of MavrickBot

Let’s break down some of the core elements of the MavrickBot contract:

Uniswap V3 Integration

The contract interacts with Uniswap V3 through the ISwapRouter interface:

interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}

function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) external view returns (uint256 amountOut);
}

This interface allows the bot to execute trades and get quotes from Uniswap V3.

Configurable Trading Parameters

To ensure flexibility, I implemented several configurable parameters:

uint256 public minTradeAmount;
uint256 public maxTradeAmount;
uint256 public tradePercent;
uint256 public slippageTolerance;
uint256 public gasPrice;
uint256 public maxGasLimit;
uint256 public profitThreshold;

These parameters can be adjusted by the contract owner to fine-tune the bot’s trading strategy.

Trade Execution

The core of the bot’s functionality lies in the executeTrade function:

function executeTrade() external onlyOwner nonReentrant {
// ... (parameter checks)

uint256 balance = IERC20(currentTrade.tokenIn).balanceOf(address(this));
uint256 tradeAmount = (balance * tradePercent) / 100;
tradeAmount = tradeAmount > currentTrade.amountIn ? currentTrade.amountIn : tradeAmount;

IERC20(currentTrade.tokenIn).approve(address(uniswapRouter), tradeAmount);

uint256 initialBalance = IERC20(currentTrade.tokenOut).balanceOf(address(this));

ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: currentTrade.tokenIn,
tokenOut: currentTrade.tokenOut,
fee: currentTrade.fee,
recipient: address(this),
deadline: block.timestamp,
amountIn: tradeAmount,
amountOutMinimum: currentTrade.minAmountOut,
sqrtPriceLimitX96: 0
});

uint256 amountOut = uniswapRouter.exactInputSingle(params);

uint256 finalBalance = IERC20(currentTrade.tokenOut).balanceOf(address(this));
uint256 profit = finalBalance - initialBalance;

require(profit >= profitThreshold, "Profit below threshold");

// ... (update balances and emit event)
}

This function checks trade parameters, calculates the trade amount, executes the trade on Uniswap V3, and verifies that the profit meets the threshold.

Security Measures

To ensure the safety of funds and prevent unauthorized access, I implemented several security features:

  1. The Ownable contract from OpenZeppelin to restrict access to critical functions.
  2. The ReentrancyGuard to prevent reentrancy attacks.
  3. Checks on allowed tokens and trade amounts.
  4. Emergency withdrawal function for quick fund retrieval if needed.

Conclusion and Next Steps

Building MavrickBot has been an exciting journey into the world of automated DeFi trading. While the contract lays a solid foundation for sandwich trading on Uniswap V3, there’s still much to explore and improve.

In the next part of this series, we’ll dive deeper into the off-chain components needed to make MavrickBot fully operational, including:

  • Monitoring the mempool for potential trade opportunities
  • Calculating optimal trade sizes and timings
  • Managing gas prices for effective trade execution
  • Implementing safeguards against front-running and other potential attacks

Stay tuned for Part 2, where we’ll bring MavrickBot to life and start hunting for those sandwich opportunities in the wild world of DeFi!

Disclaimer: This article is for educational purposes only and does not constitute financial advice. Trading cryptocurrencies carries significant risk. Always do your own research and never invest more than you can afford to lose.

--

--

Jane Karaks

Passionate writer and tech enthusiast with a knack for exploring the latest in innovation.