arbitrageEthMgs

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "arbitrageEthMgs.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.19;\r
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";\r
import "@openzeppelin/contracts/security/Pausable.sol";\r
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";\r
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";\r
interface IUniswapV2Router02 {\r
    function factory() external pure returns (address);\r
    function WETH() external pure returns (address);\r
    function swapExactTokensForTokens(uint amountIn,uint amountOutMin,address[] calldata path,address to,uint deadline) external returns (uint[] memory amounts);\r
    function getAmountsOut(uint amountIn,address[] calldata path) external view returns (uint[] memory amounts);\r
}\r
interface IUniswapV3Router {\r
    struct ExactInputSingleParams {address tokenIn;address tokenOut;uint24 fee;address recipient;uint256 deadline;uint256 amountIn;uint256 amountOutMinimum;uint160 sqrtPriceLimitX96;}\r
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);\r
}\r
interface IQuoterV2 {\r
    function quoteExactInputSingle(address tokenIn,address tokenOut,uint24 fee,uint256 amountIn,uint160 sqrtPriceLimitX96) external view returns (uint256 amountOut,uint160 sqrtPriceX96After,uint32 initializedTicksCrossed,uint256 gasEstimate);\r
}\r
interface IAsset {}\r
interface IBalancerVault {\r
    enum SwapKind { GIVEN_IN, GIVEN_OUT }\r
    struct SingleSwap {bytes32 poolId;SwapKind kind;address assetIn;address assetOut;uint256 amount;bytes userData;}\r
    struct FundManagement {address sender;bool fromInternalBalance;address payable recipient;bool toInternalBalance;}\r
    struct BatchSwapStep {bytes32 poolId;uint256 assetInIndex;uint256 assetOutIndex;uint256 amount;bytes userData;}\r
    function swap(SingleSwap memory singleSwap,FundManagement memory funds,uint256 limit,uint256 deadline) external payable returns (uint256);\r
    function queryBatchSwap(SwapKind kind,BatchSwapStep[] memory swaps,IAsset[] memory assets,FundManagement memory funds) external view returns (int256[] memory);\r
}\r
interface IPool {\r
    function flashLoanSimple(address receiverAddress,address asset,uint256 amount,bytes calldata params,uint16 referralCode) external;\r
}\r
interface IWETH {\r
    function deposit() external payable;\r
    function withdraw(uint256 amount) external;\r
}\r
contract arbitrageEthMgs is ReentrancyGuard, Pausable {\r
    using SafeERC20 for IERC20;\r
    error NotOperator();error InvalidTokens();error SameTokens();error UnsupportedTokens();error GasPriceTooHigh();error InvalidAmount();error InvalidGasLimit();error NoOpportunityFound();error OnlyWETHRoutes();error ProfitTooLow();error InvalidSlippageProtection();error NoETHSent();error InsufficientWETH();error ETHTransferFailed();error InvalidToken();error NoBalance();error InvalidDEX();error PremiumTooHigh();error InvalidGasPrice();error InvalidCaller();error InvalidInitiator();error InsufficientProfit();error NetProfitTooLow();error InvalidRecipient();error TradeSlippageExceeded();error InvalidBalancerPool();error ApproveResetFailed();error ApproveMaxFailed();error ETHOnlyFromWETH();error FunctionNotFound();error FlashLoanCooldownActive();error DailyFlashLoanLimitReached();\r
    address public constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;\r
    address public constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;\r
    address public constant UNISWAP_V3_QUOTER = 0x61fFE014bA17989E743c5F6cB21bF9697530B21e;\r
    address public constant SUSHISWAP_ROUTER = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F;\r
    address public constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;\r
    address public constant AAVE_POOL = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;\r
    address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\r
    address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\r
    address public constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;\r
    address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r
    address public constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;\r
    address public immutable operator;\r
    IPool public immutable aavePool;\r
    IWETH public immutable weth;\r
    IQuoterV2 public immutable quoterV2;\r
    struct DEXInfo {address router;uint256 fee;uint8 dexType;}\r
    struct ArbitrageParams {address tokenIn;address tokenOut;uint256 amountIn;uint256 minOutLeg1;uint256 minOutLeg2;uint8 dexIn;uint8 dexOut;uint24 uniV3FeeIn;uint24 uniV3FeeOut;bytes32 balancerPoolId;uint256 deadline;address recipient;uint256 minNetProfitWei;uint256 gasPriceWei;uint256 gasLimitEstimate;bool useOwnLiquidity;}\r
    struct OpportunityData {uint8 dexIn;uint8 dexOut;uint24 uniV3FeeIn;uint24 uniV3FeeOut;uint256 expectedProfit;uint256 minOutLeg1;uint256 minOutLeg2;uint256 gasEstimate;bool isValid;}\r
    DEXInfo[4] private dexConfigs;\r
    mapping(bytes32 => bool) public validBalancerPools;\r
    mapping(address => bool) public supportedTokens;\r
    uint256 public constant MAX_SLIPPAGE = 300;\r
    uint256 public constant MAX_TRADE_AMOUNT = 300 ether;\r
    uint256 public constant MIN_PROFIT_THRESHOLD = 0.001 ether;\r
    uint256 public constant MAX_GAS_PRICE_GWEI = 10; // Намаляваме от 30 на 10 Gwei\r
    uint256 public constant MAX_GAS_PRICE_WEI = MAX_GAS_PRICE_GWEI * 1e9;\r
    uint256 public constant GAS_OPTIMIZATION_THRESHOLD = 150000;\r
    mapping(address => uint256) public lastFlashLoan;\r
    mapping(address => uint256) public dailyFlashLoanCount;\r
    mapping(address => uint256) public lastDailyReset;\r
    uint256 public constant FLASH_LOAN_COOLDOWN = 30;\r
    uint256 public constant DAILY_FLASH_LOAN_LIMIT = 100;\r
    uint256 public totalTrades;\r
    uint256 public totalVolume;\r
    uint256 public totalProfit;\r
    uint256 public gasPriceHintWei;\r
    uint256 public flashPremiumBps = 5;\r
    bool public gasOptimizationEnabled = true;\r
    uint256 public maxGasPriceOverride = 0;\r
    event ArbitrageExecuted(address indexed user,address indexed tokenIn,address indexed tokenOut,uint256 amountIn,uint256 profit,uint8 dexIn,uint8 dexOut,bool usedOwnLiquidity);\r
    event OpportunityFound(address indexed tokenA,address indexed tokenB,uint256 amount,uint256 expectedProfit,uint8 dexIn,uint8 dexOut);\r
    event CapitalDeposited(address indexed token, uint256 amount);\r
    event CapitalWithdrawn(address indexed token, uint256 amount);\r
    event TradeLegExecuted(uint8 indexed dexId,address indexed tokenIn,address tokenOut,uint256 amountIn,uint256 amountOut);\r
    event GasPriceHintUpdated(uint256 newHintWei);\r
    event FlashPremiumBpsUpdated(uint256 newBps);\r
    event GasOptimizationToggled(bool enabled);\r
    event MaxGasPriceUpdated(uint256 newMaxPrice);\r
    constructor() {\r
        operator = msg.sender;\r
        aavePool = IPool(AAVE_POOL);\r
        weth = IWETH(WETH);\r
        quoterV2 = IQuoterV2(UNISWAP_V3_QUOTER);\r
        gasPriceHintWei = 20000000000; // 20 Gwei - по-реалистично за текущите условия\r
        dexConfigs[0] = DEXInfo({router: UNISWAP_V2_ROUTER,fee: 300,dexType: 0});\r
        dexConfigs[1] = DEXInfo({router: SUSHISWAP_ROUTER,fee: 300,dexType: 2});\r
        dexConfigs[2] = DEXInfo({router: UNISWAP_V3_ROUTER,fee: 500,dexType: 1});\r
        dexConfigs[3] = DEXInfo({router: BALANCER_VAULT,fee: 100,dexType: 3});\r
        validBalancerPools[0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014] = true;\r
        validBalancerPools[0x96646936b91d6b9d7d0c47c496afbf3d6ec7b6f8000200000000000000000019] = true;\r
        validBalancerPools[0x0b09dea16768f0799065c475be02919503cb2a3500020000000000000000001a] = true;\r
        supportedTokens[WETH] = true;supportedTokens[USDC] = true;supportedTokens[USDT] = true;supportedTokens[DAI] = true;supportedTokens[WBTC] = true;\r
    }\r
    modifier onlyOperator() {if (msg.sender != operator) revert NotOperator();_;}\r
    modifier validTokens(address tokenA, address tokenB) {if (tokenA == address(0) || tokenB == address(0)) revert InvalidTokens();if (tokenA == tokenB) revert SameTokens();if (!supportedTokens[tokenA] || !supportedTokens[tokenB]) revert UnsupportedTokens();_;}\r
    modifier rateLimited() {if (block.timestamp > lastDailyReset[msg.sender] + 1 days) {dailyFlashLoanCount[msg.sender] = 0;lastDailyReset[msg.sender] = block.timestamp;}_;}\r
    modifier gasPriceCheck() {if (gasOptimizationEnabled) {uint256 maxAllowed = maxGasPriceOverride > 0 ? maxGasPriceOverride : MAX_GAS_PRICE_WEI;if (tx.gasprice > maxAllowed) revert GasPriceTooHigh();}_;}\r
    function StartNative(uint256 maxAmount) external view returns (OpportunityData memory bestOpportunity,address tokenA,address tokenB,uint256 amount) {return _findBestNativeOpportunity(maxAmount);}\r
    function _findSimpleOpportunity(address tokenA, address tokenB, uint256 amountIn, uint24 feeIn, uint24 feeOut) internal view returns (OpportunityData memory bestOpportunity) {\r
        uint256 maxProfit = 0;\r
        (uint256 profit1, uint256 minOut1_1, uint256 minOut2_1) = _calculateProfitForRoute(tokenA, tokenB, amountIn, 0, 2, feeIn, feeOut);\r
        if (profit1 > maxProfit) {maxProfit = profit1;bestOpportunity = OpportunityData({dexIn: 0, dexOut: 2, uniV3FeeIn: feeIn, uniV3FeeOut: feeOut,expectedProfit: profit1, minOutLeg1: minOut1_1, minOutLeg2: minOut2_1,gasEstimate: _estimateGasCost(0, 2), isValid: profit1 > 0});}\r
        (uint256 profit2, uint256 minOut1_2, uint256 minOut2_2) = _calculateProfitForRoute(tokenA, tokenB, amountIn, 2, 0, feeIn, feeOut);\r
        if (profit2 > maxProfit) {bestOpportunity = OpportunityData({dexIn: 2, dexOut: 0, uniV3FeeIn: feeIn, uniV3FeeOut: feeOut,expectedProfit: profit2, minOutLeg1: minOut1_2, minOutLeg2: minOut2_2,gasEstimate: _estimateGasCost(2, 0), isValid: profit2 > 0});}\r
    }\r
    function StartNativeLite(uint256 maxAmount,address tokenB,uint24 feeIn,uint24 feeOut) external view returns (OpportunityData memory bestOpportunity,address tokenA,address tokenBOut,uint256 amount) {\r
        if (maxAmount == 0 || maxAmount > MAX_TRADE_AMOUNT) revert InvalidAmount();\r
        if (!supportedTokens[tokenB]) revert UnsupportedTokens();\r
        tokenA = WETH;tokenBOut = tokenB;amount = maxAmount / 2;\r
        if (amount == 0) return (bestOpportunity, tokenA, tokenBOut, 0);\r
        bestOpportunity = _findSimpleOpportunity(tokenA, tokenBOut, amount, feeIn, feeOut);\r
    }\r
    function _findBestNativeOpportunity(uint256 maxAmount) internal view returns (OpportunityData memory bestOpportunity,address tokenA,address tokenB,uint256 amount) {\r
        if (maxAmount == 0 || maxAmount > MAX_TRADE_AMOUNT) revert InvalidAmount();\r
        address tokenIn = WETH;\r
        address[] memory tokensOut = new address[](3);\r
        tokensOut[0] = USDC;tokensOut[1] = USDT;tokensOut[2] = DAI;\r
        uint24[1] memory v3Fees = [uint24(3000)];\r
        uint256 maxProfit = 0;\r
        for (uint j = 0; j < tokensOut.length; j++) {\r
            address tokenOut = tokensOut[j];\r
            uint256[] memory amounts = new uint256[](1);\r
            amounts[0] = maxAmount / 2;\r
            for (uint k = 0; k < amounts.length; k++) {\r
                if (amounts[k] == 0) continue;\r
                for (uint feeIn = 0; feeIn < v3Fees.length; feeIn++) {\r
                    for (uint feeOut = 0; feeOut < v3Fees.length; feeOut++) {\r
                        OpportunityData memory opp = _findOpportunity(tokenIn,tokenOut,amounts[k],v3Fees[feeIn],v3Fees[feeOut]);\r
                        if (opp.isValid && opp.expectedProfit > maxProfit) {maxProfit = opp.expectedProfit;bestOpportunity = opp;tokenA = tokenIn;tokenB = tokenOut;amount = amounts[k];}\r
                    }\r
                }\r
            }\r
        }\r
    }\r
    function AutoArbitrage(uint256 maxAmount, uint256 estimatedGasLimit) external onlyOperator nonReentrant whenNotPaused {\r
        if (maxAmount == 0 || maxAmount > MAX_TRADE_AMOUNT) revert InvalidAmount();\r
        if (estimatedGasLimit == 0 || estimatedGasLimit >= 50000000) revert InvalidGasLimit();\r
        (OpportunityData memory opportunity,address tokenA,address tokenB,uint256 bestAmount) = _findBestNativeOpportunity(maxAmount);\r
        if (!opportunity.isValid) revert NoOpportunityFound();\r
        if (tokenA != WETH) revert OnlyWETHRoutes();\r
        if (opportunity.expectedProfit < MIN_PROFIT_THRESHOLD / 5) revert ProfitTooLow();\r
        if (opportunity.minOutLeg1 == 0 || opportunity.minOutLeg2 == 0) revert InvalidSlippageProtection();\r
        if (gasOptimizationEnabled && tx.gasprice > MAX_GAS_PRICE_WEI * 5) {revert GasPriceTooHigh();}\r
        uint256 gasPrice = tx.gasprice;\r
        uint256 finalGasLimit = estimatedGasLimit > opportunity.gasEstimate ? estimatedGasLimit : opportunity.gasEstimate;\r
        ArbitrageParams memory params = ArbitrageParams({tokenIn: tokenA,tokenOut: tokenB,amountIn: bestAmount,minOutLeg1: opportunity.minOutLeg1,minOutLeg2: opportunity.minOutLeg2,dexIn: opportunity.dexIn,dexOut: opportunity.dexOut,uniV3FeeIn: opportunity.uniV3FeeIn,uniV3FeeOut: opportunity.uniV3FeeOut,balancerPoolId: _getBalancerPoolId(tokenA, tokenB),deadline: block.timestamp + 300,recipient: operator,minNetProfitWei: MIN_PROFIT_THRESHOLD / 5,gasPriceWei: gasPrice,gasLimitEstimate: finalGasLimit,useOwnLiquidity: IERC20(tokenA).balanceOf(address(this)) >= bestAmount});\r
        _executeArbWithOptionalFlash(params);\r
    }\r
    function AutoArbitrageLite(uint256 maxAmount,address tokenB,uint24 feeIn,uint24 feeOut,uint256 estimatedGasLimit) external onlyOperator nonReentrant whenNotPaused {\r
        if (maxAmount == 0 || maxAmount > MAX_TRADE_AMOUNT) revert InvalidAmount();\r
        if (estimatedGasLimit == 0 || estimatedGasLimit >= 50000000) revert InvalidGasLimit();\r
        if (!supportedTokens[tokenB]) revert UnsupportedTokens();\r
        address tokenA = WETH;\r
        uint256[2] memory samples = [maxAmount / 4, maxAmount / 2];\r
        OpportunityData memory best;uint256 bestAmount = 0;uint256 maxProfit = 0;\r
        for (uint256 i = 0; i < samples.length; i++) {\r
            uint256 amt = samples[i];\r
            if (amt == 0) continue;\r
            OpportunityData memory opp = _findOpportunity(tokenA, tokenB, amt, feeIn, feeOut);\r
            if (opp.isValid && opp.expectedProfit > maxProfit) {maxProfit = opp.expectedProfit;best = opp;bestAmount = amt;}\r
        }\r
        if (!best.isValid) revert NoOpportunityFound();\r
        if (tokenA != WETH) revert OnlyWETHRoutes();\r
        if (best.expectedProfit < MIN_PROFIT_THRESHOLD / 5) revert ProfitTooLow();\r
        if (best.minOutLeg1 == 0 || best.minOutLeg2 == 0) revert InvalidSlippageProtection();\r
        if (gasOptimizationEnabled && tx.gasprice > MAX_GAS_PRICE_WEI * 5) {revert GasPriceTooHigh();}\r
        uint256 gasPrice = tx.gasprice;\r
        uint256 finalGasLimit = estimatedGasLimit > best.gasEstimate ? estimatedGasLimit : best.gasEstimate;\r
        ArbitrageParams memory params = ArbitrageParams({tokenIn: tokenA,tokenOut: tokenB,amountIn: bestAmount,minOutLeg1: best.minOutLeg1,minOutLeg2: best.minOutLeg2,dexIn: best.dexIn,dexOut: best.dexOut,uniV3FeeIn: best.uniV3FeeIn,uniV3FeeOut: best.uniV3FeeOut,balancerPoolId: _getBalancerPoolId(tokenA, tokenB),deadline: block.timestamp + 300,recipient: operator,minNetProfitWei: MIN_PROFIT_THRESHOLD / 5,gasPriceWei: gasPrice,gasLimitEstimate: finalGasLimit,useOwnLiquidity: IERC20(tokenA).balanceOf(address(this)) >= bestAmount});\r
        _executeArbWithOptionalFlash(params);\r
    }\r
    function depositETH() external payable onlyOperator {if (msg.value == 0) revert NoETHSent();weth.deposit{value: msg.value}();emit CapitalDeposited(WETH, msg.value);}\r
    function withdrawETH(uint256 amount) external onlyOperator {if (amount == 0) revert InvalidAmount();uint256 wethBalance = IERC20(WETH).balanceOf(address(this));if (wethBalance < amount) revert InsufficientWETH();weth.withdraw(amount);(bool success,) = msg.sender.call{value: amount}("");if (!success) revert ETHTransferFailed();emit CapitalWithdrawn(WETH, amount);}\r
    function sweep(address token) external onlyOperator {if (token == address(0)) revert InvalidToken();uint256 balance = IERC20(token).balanceOf(address(this));if (balance == 0) revert NoBalance();IERC20(token).safeTransfer(msg.sender, balance);emit CapitalWithdrawn(token, balance);}\r
    function pause() external onlyOperator {_pause();}\r
    function unpause() external onlyOperator {_unpause();}\r
    function setGasPriceHint(uint256 _gasPrice) external onlyOperator {gasPriceHintWei = _gasPrice;emit GasPriceHintUpdated(_gasPrice);}\r
    function setFlashPremiumBps(uint256 _bps) external onlyOperator {if (_bps >= 100) revert PremiumTooHigh();flashPremiumBps = _bps;emit FlashPremiumBpsUpdated(_bps);}\r
    function setGasOptimization(bool _enabled) external onlyOperator {gasOptimizationEnabled = _enabled;emit GasOptimizationToggled(_enabled);}\r
    function setMaxGasPrice(uint256 _maxGasPriceGwei) external onlyOperator {if (_maxGasPriceGwei == 0 || _maxGasPriceGwei > 100) revert InvalidGasPrice();maxGasPriceOverride = _maxGasPriceGwei * 1e9;emit MaxGasPriceUpdated(maxGasPriceOverride);}\r
    function getCurrentGasInfo() external view returns (uint256 currentGasPrice,uint256 maxAllowedGasPrice,bool gasOptimizationActive,bool canExecute) {\r
        // Винаги използваме реалната gas цена от транзакцията\r
        currentGasPrice = tx.gasprice > 0 ? tx.gasprice : 2000000000; // 2 Gwei по подразбиране\r
        maxAllowedGasPrice = maxGasPriceOverride > 0 ? maxGasPriceOverride : MAX_GAS_PRICE_WEI;\r
        gasOptimizationActive = gasOptimizationEnabled;\r
        canExecute = !gasOptimizationEnabled || currentGasPrice <= maxAllowedGasPrice;\r
    }\r
    function checkGasPriceBeforeTrade() external view returns (bool canTrade) {if (!gasOptimizationEnabled) return true;uint256 maxAllowed = maxGasPriceOverride > 0 ? maxGasPriceOverride : MAX_GAS_PRICE_WEI;return tx.gasprice <= maxAllowed;}\r
    function _findOpportunity(address tokenA,address tokenB,uint256 amountIn,uint24 v3FeeIn,uint24 v3FeeOut) internal view returns (OpportunityData memory bestOpportunity) {\r
        (uint256 profit, uint256 minOut1, uint256 minOut2) = _calculateProfitForRoute(tokenA, tokenB, amountIn, 0, 2, v3FeeIn, v3FeeOut);\r
        if (profit > 0) {bestOpportunity = OpportunityData({dexIn: 0,dexOut: 2,uniV3FeeIn: v3FeeIn,uniV3FeeOut: v3FeeOut,expectedProfit: profit,minOutLeg1: minOut1,minOutLeg2: minOut2,gasEstimate: _estimateGasCost(0, 2),isValid: true});}\r
    }\r
    function _calculateProfitForRoute(address tokenA,address tokenB,uint256 amountIn,uint8 dexIn,uint8 dexOut,uint24 v3FeeIn,uint24 v3FeeOut) internal view returns (uint256 profit, uint256 minOut1, uint256 minOut2) {\r
        // Винаги използваме реалната gas цена от транзакцията\r
        uint256 effectiveGasPrice = tx.gasprice > 0 ? tx.gasprice : 2000000000; // 2 Gwei по подразбиране\r
        if (gasOptimizationEnabled && effectiveGasPrice > MAX_GAS_PRICE_WEI) {return (0, 0, 0);}\r
        // Намаляваме минималния размер на търговията за по-ниски gas цени\r
        if (amountIn < effectiveGasPrice * 200000) return (0, 0, 0);\r
        uint256 intermediateAmount = _getExpectedAmountOut(tokenA, tokenB, amountIn, dexIn, v3FeeIn);\r
        if (intermediateAmount == 0) return (0, 0, 0);\r
        minOut1 = intermediateAmount * 9700 / 10000;\r
        uint256 finalAmount = _getExpectedAmountOut(tokenB, tokenA, intermediateAmount, dexOut, v3FeeOut);\r
        if (finalAmount <= amountIn) return (0, 0, 0);\r
        minOut2 = finalAmount * 9700 / 10000;\r
        uint256 grossProfit = finalAmount - amountIn;\r
        // Намаляваме gas разходите за по-реалистични изчисления\r
        uint256 gasCost = effectiveGasPrice * _estimateGasCost(dexIn, dexOut);\r
        uint256 flashPremium = (amountIn * flashPremiumBps) / 10000;\r
        uint256 minProfit = MIN_PROFIT_THRESHOLD / 10; // Намаляваме минималната печалба\r
        uint256 totalCosts = gasCost + flashPremium + minProfit;\r
        profit = grossProfit > totalCosts ? grossProfit - totalCosts : 0;\r
    }\r
    function _getExpectedAmountOut(address tokenIn,address tokenOut,uint256 amountIn,uint8 dexId,uint24 v3Fee) internal view returns (uint256) {\r
        if (dexId >= 4) {return 0;}\r
        DEXInfo memory dex = dexConfigs[dexId];\r
        if (dex.dexType == 0 || dex.dexType == 2) {\r
            address[] memory path = new address[](2);path[0] = tokenIn;path[1] = tokenOut;\r
            try IUniswapV2Router02(dex.router).getAmountsOut(amountIn, path) returns (uint[] memory amounts) {return amounts[1];} catch {return 0;}\r
        } else if (dex.dexType == 1) {\r
            try quoterV2.quoteExactInputSingle(tokenIn,tokenOut,v3Fee,amountIn,0) returns (uint256 amountOut, uint160, uint32, uint256) {return amountOut;} catch {return 0;}\r
        } else if (dex.dexType == 3) {\r
            bytes32 poolId = _getBalancerPoolId(tokenIn, tokenOut);\r
            if (poolId == bytes32(0)) {return 0;}\r
            IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](1);\r
            swaps[0] = IBalancerVault.BatchSwapStep({poolId: poolId,assetInIndex: 0,assetOutIndex: 1,amount: amountIn,userData: ""});\r
            IAsset[] memory assets = new IAsset[](2);assets[0] = IAsset(tokenIn);assets[1] = IAsset(tokenOut);\r
            IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({sender: address(this),fromInternalBalance: false,recipient: payable(address(this)),toInternalBalance: false});\r
            try IBalancerVault(BALANCER_VAULT).queryBatchSwap(IBalancerVault.SwapKind.GIVEN_IN,swaps,assets,funds) returns (int256[] memory deltas) {return deltas[1] < 0 ? uint256(-deltas[1]) : 0;} catch {return 0;}\r
        }\r
        return 0;\r
    }\r
    function _estimateGasCost(uint8 dexIn, uint8 dexOut) internal view returns (uint256) {\r
        // Намаляваме gas оценките за по-реалистични стойности\r
        uint256 gasIn = 80000;uint256 gasOut = 80000;\r
        if (dexConfigs[dexIn].dexType == 1) {gasIn = 100000;} // Uniswap V3\r
        if (dexConfigs[dexOut].dexType == 1) {gasOut = 100000;}\r
        if (dexConfigs[dexIn].dexType == 3) {gasIn = 120000;} // Balancer\r
        if (dexConfigs[dexOut].dexType == 3) {gasOut = 120000;}\r
        return gasIn + gasOut + 40000; // Намаляваме overhead-а\r
    }\r
    function _getBalancerPoolId(address tokenA, address tokenB) internal pure returns (bytes32) {\r
        if ((tokenA == WETH && tokenB == USDC) || (tokenA == USDC && tokenB == WETH)) {return 0x96646936b91d6b9d7d0c47c496afbf3d6ec7b6f8000200000000000000000019;}\r
        if ((tokenA == WETH && tokenB == DAI) || (tokenA == DAI && tokenB == WETH)) {return 0x0b09dea16768f0799065c475be02919503cb2a3500020000000000000000001a;}\r
        if ((tokenA == WETH && tokenB == WBTC) || (tokenA == WBTC && tokenB == WETH)) {return 0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014;}\r
        return bytes32(0);\r
    }\r
    function _executeArbWithOptionalFlash(ArbitrageParams memory params) internal {\r
        bool hasOwnLiquidity = IERC20(params.tokenIn).balanceOf(address(this)) >= params.amountIn;\r
        if (hasOwnLiquidity && params.useOwnLiquidity) {\r
            uint256 balanceBefore = IERC20(params.tokenIn).balanceOf(address(this));\r
            _executeArbitrageInternal(params);\r
            uint256 balanceAfter = IERC20(params.tokenIn).balanceOf(address(this));\r
            require(balanceAfter > balanceBefore, "No profit");\r
            uint256 profit = balanceAfter - balanceBefore;\r
            uint256 gasCost = params.gasPriceWei * params.gasLimitEstimate;\r
            require(profit > gasCost + params.minNetProfitWei, "Net profit too low");\r
            if (profit > 0) {IERC20(params.tokenIn).safeTransfer(params.recipient, profit);}\r
            totalTrades++;totalVolume += params.amountIn;totalProfit += profit;\r
            emit ArbitrageExecuted(params.recipient,params.tokenIn,params.tokenOut,params.amountIn,profit,params.dexIn,params.dexOut,true);\r
        } else {_executeFlashLoanArbitrage(params);}\r
    }\r
    function _executeFlashLoanArbitrage(ArbitrageParams memory params) internal {\r
        if (block.timestamp > lastDailyReset[msg.sender] + 1 days) {dailyFlashLoanCount[msg.sender] = 0;lastDailyReset[msg.sender] = block.timestamp;}\r
        uint256 cooldownPeriod = msg.sender == operator ? 5 : FLASH_LOAN_COOLDOWN;\r
        if (block.timestamp < lastFlashLoan[msg.sender] + cooldownPeriod) {revert FlashLoanCooldownActive();}\r
        if (dailyFlashLoanCount[msg.sender] >= DAILY_FLASH_LOAN_LIMIT) {revert DailyFlashLoanLimitReached();}\r
        lastFlashLoan[msg.sender] = block.timestamp;dailyFlashLoanCount[msg.sender]++;\r
        bytes memory paramsData = abi.encode(params, msg.sender);\r
        aavePool.flashLoanSimple(address(this),params.tokenIn,params.amountIn,paramsData,0);\r
    }\r
    function executeOperation(address asset,uint256 amount,uint256 premium,address initiator,bytes calldata params) external returns (bool) {\r
        if (msg.sender != address(aavePool)) {revert InvalidCaller();}\r
        if (initiator != address(this)) {revert InvalidInitiator();}\r
        (ArbitrageParams memory arbParams, address originalUser) = abi.decode(params, (ArbitrageParams, address));\r
        _executeArbitrageInternal(arbParams);\r
        uint256 balanceAfter = IERC20(asset).balanceOf(address(this));\r
        uint256 totalDebt = amount + premium;\r
        if (balanceAfter < totalDebt) {revert InsufficientProfit();}\r
        uint256 profit = balanceAfter - totalDebt;\r
        uint256 gasCost = arbParams.gasPriceWei * arbParams.gasLimitEstimate;\r
        if (profit < gasCost + arbParams.minNetProfitWei) {revert NetProfitTooLow();}\r
        _approveMaxIfNeeded(asset, address(aavePool), totalDebt);\r
        _finalizeArbitrage(asset, originalUser, profit, arbParams);\r
        return true;\r
    }\r
    function _finalizeArbitrage(address asset,address user,uint256 profit,ArbitrageParams memory params) internal {\r
        if (profit > 0) {IERC20(asset).safeTransfer(user, profit);}\r
        totalTrades++;totalVolume += params.amountIn;totalProfit += profit;\r
        emit ArbitrageExecuted(user,params.tokenIn,params.tokenOut,params.amountIn,profit,params.dexIn,params.dexOut,false);\r
    }\r
    function _executeArbitrageInternal(ArbitrageParams memory params) internal {\r
        if (params.recipient == address(0)) {revert InvalidRecipient();}\r
        uint256 intermediateAmount = _executeTrade(params.tokenIn,params.tokenOut,params.amountIn,params.minOutLeg1,params.dexIn,params.uniV3FeeIn,params.balancerPoolId,params.deadline);\r
        _executeTrade(params.tokenOut,params.tokenIn,intermediateAmount,params.minOutLeg2,params.dexOut,params.uniV3FeeOut,params.balancerPoolId,params.deadline);\r
    }\r
    function _executeTrade(address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,uint8 dexId,uint24 uniV3Fee,bytes32 balancerPoolId,uint256 deadline) internal returns (uint256 amountOut) {\r
        DEXInfo memory dex = dexConfigs[dexId];\r
        if (dex.dexType == 0 || dex.dexType == 2) {amountOut = _executeV2Trade(tokenIn, tokenOut, amountIn, minAmountOut, dex.router, deadline);} \r
        else if (dex.dexType == 1) {amountOut = _executeV3Trade(tokenIn, tokenOut, amountIn, minAmountOut, uniV3Fee, deadline);} \r
        else if (dex.dexType == 3) {amountOut = _executeBalancerTrade(tokenIn, tokenOut, amountIn, minAmountOut, balancerPoolId, deadline);}\r
        emit TradeLegExecuted(dexId, tokenIn, tokenOut, amountIn, amountOut);\r
    }\r
    function _executeV2Trade(address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,address router,uint256 deadline) internal returns (uint256) {\r
        _approveMaxIfNeeded(tokenIn, router, amountIn);\r
        address[] memory path = new address[](2);path[0] = tokenIn;path[1] = tokenOut;\r
        uint256[] memory amounts = IUniswapV2Router02(router).swapExactTokensForTokens(amountIn,minAmountOut,path,address(this),deadline);\r
        return amounts[1];\r
    }\r
    function _executeV3Trade(address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,uint24 fee,uint256 deadline) internal returns (uint256) {\r
        _approveMaxIfNeeded(tokenIn, UNISWAP_V3_ROUTER, amountIn);\r
        IUniswapV3Router.ExactInputSingleParams memory params = IUniswapV3Router.ExactInputSingleParams({tokenIn: tokenIn,tokenOut: tokenOut,fee: fee,recipient: address(this),deadline: deadline,amountIn: amountIn,amountOutMinimum: minAmountOut,sqrtPriceLimitX96: 0});\r
        return IUniswapV3Router(UNISWAP_V3_ROUTER).exactInputSingle(params);\r
    }\r
    function _executeBalancerTrade(address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,bytes32 poolId,uint256 deadline) internal returns (uint256) {\r
        if (!validBalancerPools[poolId]) {revert InvalidBalancerPool();}\r
        _approveMaxIfNeeded(tokenIn, BALANCER_VAULT, amountIn);\r
        IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap({poolId: poolId,kind: IBalancerVault.SwapKind.GIVEN_IN,assetIn: tokenIn,assetOut: tokenOut,amount: amountIn,userData: ""});\r
        IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({sender: address(this),fromInternalBalance: false,recipient: payable(address(this)),toInternalBalance: false});\r
        return IBalancerVault(BALANCER_VAULT).swap(singleSwap, funds, minAmountOut, deadline);\r
    }\r
    function _approveMaxIfNeeded(address token, address spender, uint256 amount) internal {\r
        uint256 current = IERC20(token).allowance(address(this), spender);\r
        if (current < amount) {IERC20(token).forceApprove(spender, 0);IERC20(token).forceApprove(spender, type(uint256).max);}\r
    }\r
    function GetStatus() external view returns (uint256 contractTotalTrades,uint256 contractTotalVolume,uint256 contractTotalProfit,bool canTrade,uint256 contractWETHBalance) {\r
        contractTotalTrades = totalTrades;contractTotalVolume = totalVolume;contractTotalProfit = totalProfit;\r
        uint256 timeSince = block.timestamp > lastFlashLoan[msg.sender] ? block.timestamp - lastFlashLoan[msg.sender] : 0;\r
        uint256 cooldown = timeSince >= FLASH_LOAN_COOLDOWN ? 0 : FLASH_LOAN_COOLDOWN - timeSince;\r
        canTrade = cooldown == 0 && dailyFlashLoanCount[msg.sender] < DAILY_FLASH_LOAN_LIMIT && !paused();\r
        contractWETHBalance = IERC20(WETH).balanceOf(address(this));\r
    }\r
    function isTokenSupported(address token) external view returns (bool) {return supportedTokens[token];}\r
    function getDEXInfo(uint8 dexId) external view returns (address router, uint256 fee, uint8 dexType) {if (dexId >= 4) {revert InvalidDEX();}DEXInfo memory dex = dexConfigs[dexId];return (dex.router, dex.fee, dex.dexType);}\r
    function isValidBalancerPool(bytes32 poolId) external view returns (bool) {return validBalancerPools[poolId];}\r
    function getUserCooldown(address user) external view returns (uint256) {uint256 timeSince = block.timestamp > lastFlashLoan[user] ? block.timestamp - lastFlashLoan[user] : 0;return timeSince >= FLASH_LOAN_COOLDOWN ? 0 : FLASH_LOAN_COOLDOWN - timeSince;}\r
    function getOpportunityDetails(uint256 maxAmount) external view returns (bool opportunityFound,uint256 expectedProfit,uint256 currentThreshold,uint256 gasEstimate,bool gasOptimizationActive,uint256 currentGasPrice) {\r
        (OpportunityData memory opportunity, , , ) = _findBestNativeOpportunity(maxAmount);\r
        return (opportunity.isValid,opportunity.expectedProfit,MIN_PROFIT_THRESHOLD / 5,opportunity.gasEstimate,gasOptimizationEnabled,tx.gasprice);\r
    }\r
    function QuickCheck(uint256 maxAmount, address tokenB) external view returns (bool hasOpportunity, uint256 estimatedProfit) {\r
        if (maxAmount == 0 || !supportedTokens[tokenB]) {return (false, 0);}\r
        uint256 amt1 = _getExpectedAmountOut(WETH, tokenB, maxAmount/2, 0, 3000);\r
        if (amt1 == 0) {return (false, 0);}\r
        uint256 amt2 = _getExpectedAmountOut(tokenB, WETH, amt1, 2, 3000);\r
        if (amt2 <= maxAmount/2) {return (false, 0);}\r
        return (true, amt2 - maxAmount/2);\r
    }\r
    function StartNativeSimple(uint256 maxAmount, address tokenOut) external view returns (bool found, uint256 expectedProfit) {\r
        if (maxAmount == 0 || maxAmount > MAX_TRADE_AMOUNT) {revert InvalidAmount();}\r
        if (!supportedTokens[tokenOut]) {revert UnsupportedTokens();}\r
        OpportunityData memory opp = _findOpportunity(WETH, tokenOut, maxAmount/2, 3000, 3000);\r
        return (opp.isValid, opp.expectedProfit);\r
    }\r
    \r
    // Нова функция за тестване на gas изчисленията\r
    function testGasCalculation(uint256 amountIn, address tokenOut) external view returns (\r
        uint256 currentGasPrice,\r
        uint256 estimatedGasCost,\r
        uint256 gasCostInWei,\r
        uint256 minTradeSize,\r
        bool canTrade\r
    ) {\r
        currentGasPrice = tx.gasprice > 0 ? tx.gasprice : 2000000000;\r
        estimatedGasCost = _estimateGasCost(0, 2);\r
        gasCostInWei = currentGasPrice * estimatedGasCost;\r
        minTradeSize = currentGasPrice * 200000;\r
        canTrade = amountIn >= minTradeSize && currentGasPrice <= MAX_GAS_PRICE_WEI;\r
    }\r
    receive() external payable {if (msg.sender != WETH) {revert ETHOnlyFromWETH();}}\r
    fallback() external payable {revert FunctionNotFound();}\r
}"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
    },
    "@openzeppelin/contracts/security/Pausable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
"
    },
    "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.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 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;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @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.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @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) {
        return _status == _ENTERED;
    }
}
"
    },
    "@openzeppelin/contracts/interfaces/IERC1363.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    },
    "@openzeppelin/contracts/interfaces/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";
"
    },
    "@openzeppelin/contracts/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";
"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 800
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
ERC20, ERC165, Proxy, Pausable, Swap, Upgradeable, Factory|addr:0x4c08a1e8e985e6e27d1cba100977b701fbe5c746|verified:true|block:23453658|tx:0x4d15f0dd3e1dbc0e81b7c2c5c5ccc505ab840a7a7f6339d7834a4a65e9c4f5e1|first_check:1758969531

Submitted on: 2025-09-27 12:38:53

Comments

Log in to comment.

No comments yet.