FlashArb_Aave_1inchV6_0x_Sushi

Description:

Decentralized Finance (DeFi) protocol contract providing Swap functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/* ====================== Minimal Interfaces ====================== */

interface IERC20 {
    function balanceOf(address a) external view returns (uint256);
    function allowance(address o, address s) external view returns (uint256);
    function approve(address s, uint256 a) external returns (bool);
    function transfer(address to, uint256 a) external returns (bool);
    function transferFrom(address f, address t, uint256 a) external returns (bool);
    function decimals() external view returns (uint8);
}

interface IWETH is IERC20 {
    function deposit() external payable;
    function withdraw(uint256) external;
}

/* UniswapV2 / SushiV2 router */
interface IUniswapV2Router02 {
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
}

/* 1inch Aggregation Router v6 */
interface IAggregationRouterV6 {
    struct SwapDescription {
        address srcToken;
        address dstToken;
        address receiver;
        address dstReceiver;
        uint256 amount;
        uint256 minReturnAmount;
        uint256 flags;
        bytes permit;
    }

    function swap(
        address executor,
        SwapDescription calldata desc,
        bytes calldata data
    ) external payable returns (uint256 returnAmount, uint256 spentAmount);
}

/* Aave v3 flash loan (simple) */
interface IPool {
    function flashLoanSimple(
        address receiverAddress,
        address asset,
        uint256 amount,
        bytes calldata params,
        uint16 referralCode
    ) external;
}
interface IFlashLoanSimpleReceiver {
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external returns (bool);
}

/* ====================== Ownable + Reentrancy ====================== */

abstract contract Ownable {
    address public owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; }
    constructor() { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); }
    function transferOwnership(address next) external onlyOwner {
        require(next != address(0), "zero");
        emit OwnershipTransferred(owner, next);
        owner = next;
    }
}

abstract contract ReentrancyGuard {
    uint256 private locked = 1;
    modifier nonReentrant() { require(locked == 1, "reentrancy"); locked = 2; _; locked = 1; }
}

/* ============================= MAIN ============================= */

contract FlashArb_Aave_1inchV6_0x_Sushi is IFlashLoanSimpleReceiver, Ownable, ReentrancyGuard {
    /* -------- Hard-coded mainnet addresses -------- */
    IPool public immutable aavePool = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
    IERC20 public immutable USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
    IWETH public immutable WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    IAggregationRouterV6 public immutable oneInchV6 =
        IAggregationRouterV6(0x111111125421cA6dc452d289314280a0f8842A65);
    IUniswapV2Router02 public immutable sushiRouter =
        IUniswapV2Router02(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);

    /* -------- Strategy params -------- */
    uint256 public flashLoanAmountUSDC = 5_002_155 * 1e6;
    uint256 public buyPriceMaxUsdE6 = 4_482_000000; // buy ceiling: $4,482 * 1e6 per ETH
    uint256 public sellPriceMinUsdE6 = 4_488_000000; // sell floor: $4,488 * 1e6 per ETH
    address public profitReceiver = msg.sender;

    event Executed(uint8 route, uint256 usdcSpent, uint256 wethBought, uint256 usdcReceived, uint256 premium, int256 profit);
    event ParamsUpdated(uint256 amountUSDC, uint256 buyMax, uint256 sellMin);
    event ProfitReceiverUpdated(address to);

    /* ---------------- Admin ---------------- */
    function setParams(uint256 amountUSDC, uint256 buyMaxE6, uint256 sellMinE6) external onlyOwner {
        require(amountUSDC > 0 && buyMaxE6 > 0 && sellMinE6 > 0, "bad params");
        flashLoanAmountUSDC = amountUSDC;
        buyPriceMaxUsdE6 = buyMaxE6;
        sellPriceMinUsdE6 = sellMinE6;
        emit ParamsUpdated(amountUSDC, buyMaxE6, sellMinE6);
    }

    function setProfitReceiver(address to) external onlyOwner {
        require(to != address(0), "zero");
        profitReceiver = to;
        emit ProfitReceiverUpdated(to);
    }

    /* ---------------- Start 1inch (raw calldata version) ----------------
       Pack: routeType=1 | routerCalldata
       routerCalldata = tx.data from 1inch API for AggregationRouterV6.swap
    ----------------------------------------------------- */
    function startArb1inchRaw(bytes calldata routerCalldata)
        external onlyOwner nonReentrant
    {
        bytes memory packed = abi.encode(uint8(1), routerCalldata);
        aavePool.flashLoanSimple(address(this), address(USDC), flashLoanAmountUSDC, packed, 0);
    }

    /* ---------------- Start (0x path) ----------------
       Pack: routeType=2 | target | allowanceTarget | callData | minWethOutHint
    -------------------------------------------------- */
    function startArb0x(
        address target,
        address allowanceTarget,
        bytes calldata callData,
        uint256 minWethOutHint
    ) external onlyOwner nonReentrant {
        require(target != address(0) && allowanceTarget != address(0), "bad target");
        bytes memory packed = abi.encode(uint8(2), target, allowanceTarget, callData, minWethOutHint);
        aavePool.flashLoanSimple(address(this), address(USDC), flashLoanAmountUSDC, packed, 0);
    }

    /* ---------------- Aave callback ---------------- */
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external override returns (bool) {
        require(msg.sender == address(aavePool), "caller!=pool");
        require(initiator == address(this), "initiator!=this");
        require(asset == address(USDC), "asset!=USDC");
        require(amount == flashLoanAmountUSDC, "amount mismatch");

        (uint8 route,) = abi.decode(params, (uint8, bytes));

        uint256 wethBought;
        if (route == 1) {
            wethBought = _buyVia1inchRaw(amount, params);
        } else if (route == 2) {
            wethBought = _buyVia0x(amount, params);
        } else {
            revert("unknown route");
        }

        uint256 usdcReceived = _sellOnSushi(wethBought);

        _repayAndDistribute(amount, premium);

        emit Executed(route, amount, wethBought, usdcReceived, premium, int256(0));
        return true;
    }

    /* ---------------- Internals ---------------- */

    // routeType=1 payload: (uint8, bytes routerCalldata)
    function _buyVia1inchRaw(uint256 usdcIn, bytes calldata packed) private returns (uint256 bought) {
    (, bytes memory callData) = abi.decode(packed, (uint8, bytes));

    uint256 wBefore = WETH.balanceOf(address(this));
    _approveIfNeeded(USDC, address(oneInchV6), usdcIn);

    (bool ok, ) = address(oneInchV6).call(callData);  // <-- Fixed: Removed `ret`
    require(ok, "1inch v6 swap failed");

    bought = WETH.balanceOf(address(this)) - wBefore;
    uint256 minByPrice = (usdcIn * 1e18) / buyPriceMaxUsdE6;
    require(bought >= minByPrice, "bought < ceiling");
}

    // routeType=2 payload: (uint8, address target, address allowanceTarget, bytes data, uint256 minWethOutHint)
    function _buyVia0x(uint256 usdcIn, bytes calldata packed) private returns (uint256 bought) {
        ( , address target, address allowanceTarget, bytes memory data, uint256 minWethOutHint) =
            abi.decode(packed, (uint8, address, address, bytes, uint256));

        _approveIfNeeded(USDC, allowanceTarget, usdcIn);

        uint256 wBefore = WETH.balanceOf(address(this));
        (bool ok, ) = target.call(data);
        require(ok, "0x swap failed");
        bought = WETH.balanceOf(address(this)) - wBefore;

        uint256 ceiling = (usdcIn * 1e18) / buyPriceMaxUsdE6;
        if (minWethOutHint < ceiling) { minWethOutHint = ceiling; }
        require(bought >= minWethOutHint, "bought < min");
    }

    function _sellOnSushi(uint256 wethIn) private returns (uint256 usdcReceived) {
        uint256 minOut = (wethIn * sellPriceMinUsdE6) / 1e18;
        _approveIfNeeded(WETH, address(sushiRouter), wethIn);

        address[] memory path = new address[](2);
        path[0] = address(WETH);
        path[1] = address(USDC);

        uint256 beforeBal = USDC.balanceOf(address(this));
        sushiRouter.swapExactTokensForTokens(
            wethIn,
            minOut,
            path,
            address(this),
            block.timestamp
        );
        usdcReceived = USDC.balanceOf(address(this)) - beforeBal;
        require(usdcReceived >= minOut, "sell below floor");
    }

      function _repayAndDistribute(uint256 amount, uint256 premium) private {
        uint256 repayAmt = amount + premium;
        _approveIfNeeded(USDC, address(aavePool), repayAmt); // Aave pulls via allowance

        uint256 bal = USDC.balanceOf(address(this));
        if (bal > repayAmt) {
            unchecked { USDC.transfer(profitReceiver, bal - repayAmt); }
        }
    }

    function _approveIfNeeded(IERC20 token, address spender, uint256 amount) private {
        if (token.allowance(address(this), spender) < amount) {
            require(token.approve(spender, type(uint256).max), "approve fail");
        }
    }

    /* Rescue tokens (if any dust remains) */
    function rescue(address token, uint256 amount, address to) external onlyOwner {
        IERC20(token).transfer(to, amount);
    }
}

Tags:
ERC20, DeFi, Swap|addr:0x8481ef13ebdfee2ddffd9a18b8f8a3efd8327b4c|verified:true|block:23410853|tx:0xe3159ed7e54bed1c94b327f036ddcc1f0b539ab4cbf6fd695535d20c0210fce5|first_check:1758463530

Submitted on: 2025-09-21 16:05:31

Comments

Log in to comment.

No comments yet.