BalancerFlashloanArbitrage

Description:

Decentralized Finance (DeFi) protocol contract providing Swap, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/BalancerFlashloanArbitrage.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.19;\r
\r
// Simple ownership contract\r
contract Ownable {\r
    address private _owner;\r
    \r
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r
    \r
    constructor() {\r
        _owner = msg.sender;\r
        emit OwnershipTransferred(address(0), msg.sender);\r
    }\r
    \r
    modifier onlyOwner() {\r
        require(_owner == msg.sender, "Ownable: caller is not the owner");\r
        _;\r
    }\r
    \r
    function owner() public view returns (address) {\r
        return _owner;\r
    }\r
    \r
    function transferOwnership(address newOwner) public onlyOwner {\r
        require(newOwner != address(0), "Ownable: new owner is the zero address");\r
        emit OwnershipTransferred(_owner, newOwner);\r
        _owner = newOwner;\r
    }\r
}\r
\r
// Simple reentrancy guard\r
contract ReentrancyGuard {\r
    uint256 private constant _NOT_ENTERED = 1;\r
    uint256 private constant _ENTERED = 2;\r
    uint256 private _status;\r
    \r
    constructor() {\r
        _status = _NOT_ENTERED;\r
    }\r
    \r
    modifier nonReentrant() {\r
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");\r
        _status = _ENTERED;\r
        _;\r
        _status = _NOT_ENTERED;\r
    }\r
}\r
\r
// ERC20 Interface\r
interface IERC20 {\r
    function totalSupply() external view returns (uint256);\r
    function balanceOf(address account) external view returns (uint256);\r
    function transfer(address to, uint256 amount) external returns (bool);\r
    function allowance(address owner, address spender) external view returns (uint256);\r
    function approve(address spender, uint256 amount) external returns (bool);\r
    function transferFrom(address from, address to, uint256 amount) external returns (bool);\r
}\r
\r
// Balancer V2 Interfaces\r
interface IBalancerVault {\r
    function flashLoan(\r
        address recipient,\r
        address[] memory tokens,\r
        uint256[] memory amounts,\r
        bytes memory userData\r
    ) external;\r
}\r
\r
interface IFlashLoanRecipient {\r
    function receiveFlashLoan(\r
        address[] memory tokens,\r
        uint256[] memory amounts,\r
        uint256[] memory feeAmounts,\r
        bytes memory userData\r
    ) external;\r
}\r
\r
// Uniswap V2 Interface\r
interface IUniswapV2Router {\r
    function swapExactTokensForTokens(\r
        uint amountIn,\r
        uint amountOutMin,\r
        address[] calldata path,\r
        address to,\r
        uint deadline\r
    ) external returns (uint[] memory amounts);\r
    \r
    function getAmountsOut(uint amountIn, address[] calldata path)\r
        external view returns (uint[] memory amounts);\r
}\r
\r
// WETH Interface\r
interface IWETH {\r
    function deposit() external payable;\r
    function withdraw(uint256) external;\r
    function balanceOf(address) external view returns (uint256);\r
    function transfer(address, uint256) external returns (bool);\r
    function approve(address, uint256) external returns (bool);\r
}\r
\r
/**\r
 * @title BalancerFlashloanArbitrage\r
 * @dev Real flashloan arbitrage contract using Balancer V2 (0% fees)\r
 * @notice Executes profitable arbitrage between DEXs using FREE flashloans\r
 */\r
contract BalancerFlashloanArbitrage is IFlashLoanRecipient, Ownable, ReentrancyGuard {\r
\r
    // ???? Balancer V2 Vault (FREE flashloans)\r
    IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);\r
    \r
    // ???? DEX Routers\r
    IUniswapV2Router public constant UNISWAP_V2 = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);\r
    IUniswapV2Router public constant SUSHISWAP = IUniswapV2Router(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);\r
    \r
    // ???? Token addresses\r
    address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\r
    address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r
    \r
    // ???? Trading parameters\r
    uint256 public minProfitBasisPoints = 10; // 0.1% minimum profit\r
    uint256 public maxSlippageBasisPoints = 50; // 0.5% max slippage\r
    \r
    // ???? Events\r
    event FlashloanArbitrageExecuted(\r
        address indexed token,\r
        uint256 flashloanAmount,\r
        uint256 profit,\r
        address buyDex,\r
        address sellDex\r
    );\r
    \r
    event ProfitWithdrawn(address indexed owner, uint256 amount);\r
    \r
    // ???? Modifiers\r
    modifier onlyBalancerVault() {\r
        require(msg.sender == address(BALANCER_VAULT), "Only Balancer Vault");\r
        _;\r
    }\r
\r
    constructor() {}\r
\r
    /**\r
     * @dev Initiate flashloan arbitrage\r
     * @param flashloanAmount Amount to borrow (in WETH wei)\r
     * @param buyDexRouter Router to buy on (cheaper)\r
     * @param sellDexRouter Router to sell on (expensive)\r
     */\r
    function executeFlashloanArbitrage(\r
        uint256 flashloanAmount,\r
        address buyDexRouter,\r
        address sellDexRouter\r
    ) external onlyOwner nonReentrant {\r
        require(flashloanAmount > 0, "Invalid flashloan amount");\r
        require(buyDexRouter != sellDexRouter, "Same DEX");\r
        require(\r
            buyDexRouter == address(UNISWAP_V2) || buyDexRouter == address(SUSHISWAP),\r
            "Invalid buy DEX"\r
        );\r
        require(\r
            sellDexRouter == address(UNISWAP_V2) || sellDexRouter == address(SUSHISWAP),\r
            "Invalid sell DEX"\r
        );\r
\r
        // ???? Prepare flashloan data\r
        address[] memory tokens = new address[](1);\r
        tokens[0] = WETH;\r
        \r
        uint256[] memory amounts = new uint256[](1);\r
        amounts[0] = flashloanAmount;\r
        \r
        // ???? Encode arbitrage parameters\r
        bytes memory userData = abi.encode(buyDexRouter, sellDexRouter, flashloanAmount);\r
        \r
        // ???? Execute FREE Balancer flashloan\r
        BALANCER_VAULT.flashLoan(address(this), tokens, amounts, userData);\r
    }\r
\r
    /**\r
     * @dev Balancer flashloan callback - THE CORE ARBITRAGE LOGIC\r
     * @param tokens Array of tokens (WETH)\r
     * @param amounts Array of amounts borrowed\r
     * @param feeAmounts Array of fees (0 for Balancer!)\r
     * @param userData Encoded arbitrage parameters\r
     */\r
    function receiveFlashLoan(\r
        address[] memory tokens,\r
        uint256[] memory amounts,\r
        uint256[] memory feeAmounts,\r
        bytes memory userData\r
    ) external override onlyBalancerVault {\r
        require(tokens.length == 1 && tokens[0] == WETH, "Invalid token");\r
        require(amounts.length == 1 && amounts[0] > 0, "Invalid amount");\r
        require(feeAmounts[0] == 0, "Balancer should be fee-free");\r
\r
        // ???? Decode arbitrage parameters\r
        (address buyDexRouter, address sellDexRouter, uint256 flashloanAmount) = \r
            abi.decode(userData, (address, address, uint256));\r
\r
        // ???? Borrowed amount verification\r
        require(amounts[0] == flashloanAmount, "Amount mismatch");\r
        require(IERC20(WETH).balanceOf(address(this)) >= flashloanAmount, "Insufficient WETH received");\r
\r
        // ???? EXECUTE ARBITRAGE STRATEGY\r
        uint256 profit = _executeArbitrageStrategy(\r
            flashloanAmount,\r
            buyDexRouter,\r
            sellDexRouter\r
        );\r
\r
        // ???? Repay flashloan (amount + fees, but fees = 0!)\r
        uint256 totalRepayment = amounts[0] + feeAmounts[0]; // feeAmounts[0] = 0\r
        require(\r
            IERC20(WETH).balanceOf(address(this)) >= totalRepayment,\r
            "Insufficient WETH for repayment"\r
        );\r
\r
        // ???? Repay flashloan to Balancer\r
        require(IERC20(WETH).transfer(address(BALANCER_VAULT), totalRepayment), "Repayment failed");\r
\r
        // ???? Emit success event\r
        emit FlashloanArbitrageExecuted(\r
            WETH,\r
            flashloanAmount,\r
            profit,\r
            buyDexRouter,\r
            sellDexRouter\r
        );\r
    }\r
\r
    /**\r
     * @dev Execute the actual arbitrage strategy\r
     * @param flashloanAmount Amount borrowed\r
     * @param buyDexRouter DEX to buy on (cheaper)\r
     * @param sellDexRouter DEX to sell on (expensive)\r
     * @return profit Profit earned from arbitrage\r
     */\r
    function _executeArbitrageStrategy(\r
        uint256 flashloanAmount,\r
        address buyDexRouter,\r
        address sellDexRouter\r
    ) internal returns (uint256 profit) {\r
        uint256 initialWETH = IERC20(WETH).balanceOf(address(this));\r
\r
        // ???? Step 1: Convert WETH to DAI on cheaper DEX\r
        uint256 daiReceived = _swapWETHForDAI(flashloanAmount, buyDexRouter);\r
        require(daiReceived > 0, "No DAI received");\r
\r
        // ???? Step 2: Convert DAI back to WETH on expensive DEX\r
        uint256 wethReceived = _swapDAIForWETH(daiReceived, sellDexRouter);\r
        require(wethReceived > 0, "No WETH received");\r
\r
        // ???? Calculate profit\r
        uint256 finalWETH = IERC20(WETH).balanceOf(address(this));\r
        require(finalWETH >= initialWETH, "Trade resulted in loss");\r
        \r
        profit = finalWETH - initialWETH;\r
        require(profit > 0, "No profit achieved");\r
\r
        // ???? Verify minimum profit\r
        uint256 minProfit = (flashloanAmount * minProfitBasisPoints) / 10000;\r
        require(profit >= minProfit, "Insufficient profit");\r
\r
        return profit;\r
    }\r
\r
    /**\r
     * @dev Swap WETH for DAI on specified DEX\r
     */\r
    function _swapWETHForDAI(uint256 wethAmount, address dexRouter) internal returns (uint256) {\r
        require(IERC20(WETH).approve(dexRouter, wethAmount), "WETH approval failed");\r
\r
        address[] memory path = new address[](2);\r
        path[0] = WETH;\r
        path[1] = DAI;\r
\r
        uint256[] memory amounts = IUniswapV2Router(dexRouter).swapExactTokensForTokens(\r
            wethAmount,\r
            0, // Accept any amount of DAI\r
            path,\r
            address(this),\r
            block.timestamp + 300\r
        );\r
\r
        return amounts[1]; // DAI received\r
    }\r
\r
    /**\r
     * @dev Swap DAI for WETH on specified DEX\r
     */\r
    function _swapDAIForWETH(uint256 daiAmount, address dexRouter) internal returns (uint256) {\r
        require(IERC20(DAI).approve(dexRouter, daiAmount), "DAI approval failed");\r
\r
        address[] memory path = new address[](2);\r
        path[0] = DAI;\r
        path[1] = WETH;\r
\r
        uint256[] memory amounts = IUniswapV2Router(dexRouter).swapExactTokensForTokens(\r
            daiAmount,\r
            0, // Accept any amount of WETH\r
            path,\r
            address(this),\r
            block.timestamp + 300\r
        );\r
\r
        return amounts[1]; // WETH received\r
    }\r
\r
    /**\r
     * @dev Check arbitrage opportunity before execution\r
     */\r
    function checkArbitrageOpportunity(\r
        uint256 flashloanAmount,\r
        address buyDexRouter,\r
        address sellDexRouter\r
    ) external view returns (\r
        bool profitable,\r
        uint256 estimatedProfit,\r
        uint256 buyPrice,\r
        uint256 sellPrice\r
    ) {\r
        // Get prices from both DEXs\r
        address[] memory path = new address[](2);\r
        path[0] = WETH;\r
        path[1] = DAI;\r
\r
        uint256[] memory buyAmounts = IUniswapV2Router(buyDexRouter).getAmountsOut(flashloanAmount, path);\r
        uint256 daiFromBuy = buyAmounts[1];\r
\r
        path[0] = DAI;\r
        path[1] = WETH;\r
        uint256[] memory sellAmounts = IUniswapV2Router(sellDexRouter).getAmountsOut(daiFromBuy, path);\r
        uint256 wethFromSell = sellAmounts[1];\r
\r
        if (wethFromSell > flashloanAmount) {\r
            estimatedProfit = wethFromSell - flashloanAmount;\r
            uint256 minProfit = (flashloanAmount * minProfitBasisPoints) / 10000;\r
            profitable = estimatedProfit >= minProfit;\r
        }\r
\r
        buyPrice = daiFromBuy;\r
        sellPrice = wethFromSell;\r
    }\r
\r
    /**\r
     * @dev Withdraw profits to owner\r
     */\r
    function withdrawProfits() external onlyOwner {\r
        uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\r
        require(wethBalance > 0, "No WETH to withdraw");\r
\r
        require(IERC20(WETH).transfer(owner(), wethBalance), "WETH transfer failed");\r
        emit ProfitWithdrawn(owner(), wethBalance);\r
    }\r
\r
    /**\r
     * @dev Withdraw any ERC20 token (emergency)\r
     */\r
    function withdrawToken(address token, uint256 amount) external onlyOwner {\r
        require(token != address(0), "Invalid token");\r
        require(IERC20(token).transfer(owner(), amount), "Token transfer failed");\r
    }\r
\r
    /**\r
     * @dev Withdraw ETH (emergency)\r
     */\r
    function withdrawETH() external onlyOwner {\r
        uint256 balance = address(this).balance;\r
        require(balance > 0, "No ETH to withdraw");\r
        payable(owner()).transfer(balance);\r
    }\r
\r
    /**\r
     * @dev Update trading parameters\r
     */\r
    function updateTradingParams(\r
        uint256 _minProfitBasisPoints,\r
        uint256 _maxSlippageBasisPoints\r
    ) external onlyOwner {\r
        require(_minProfitBasisPoints <= 1000, "Max 10% min profit"); // Max 10%\r
        require(_maxSlippageBasisPoints <= 1000, "Max 10% slippage"); // Max 10%\r
        \r
        minProfitBasisPoints = _minProfitBasisPoints;\r
        maxSlippageBasisPoints = _maxSlippageBasisPoints;\r
    }\r
\r
    /**\r
     * @dev Receive ETH\r
     */\r
    receive() external payable {}\r
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "viaIR": true,
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
ERC20, DeFi, Swap, Factory|addr:0x25283af8d286ef946d2561935ca597b9affd9d36|verified:true|block:23710478|tx:0x7149fc0b406649bde6dcfa1d4145115baab5ffc9748ed7376f807efff8b286c8|first_check:1762082841

Submitted on: 2025-11-02 12:27:22

Comments

Log in to comment.

No comments yet.