S Price: $0.578734 (-3.05%)

Contract Diff Checker

Contract Name:
FARMER

Contract Source Code:

File 1 of 1 : FARMER

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

// OpenZeppelin Contracts v5.0.1

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 */
abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "R1");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism
 */
abstract contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert("O1");
        }
        _transferOwnership(initialOwner);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "O2");
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "O1");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/**
 * @dev Implementation of the {IERC20} interface.
 */
abstract contract ERC20 is IERC20 {
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;
    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        address owner = msg.sender;
        _transfer(owner, to, amount);
        return true;
    }

    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        address owner = msg.sender;
        _approve(owner, spender, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
        address spender = msg.sender;
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0) && to != address(0), "E0");
        _beforeTokenTransfer(from, to, amount);
        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "E2");
        unchecked {
            _balances[from] = fromBalance - amount;
            _balances[to] += amount;
        }
        emit Transfer(from, to, amount);
        _afterTokenTransfer(from, to, amount);
    }

    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "E3");
        _beforeTokenTransfer(address(0), account, amount);
        _totalSupply += amount;
        unchecked {
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);
        _afterTokenTransfer(address(0), account, amount);
    }

    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0) && spender != address(0), "E4");
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "E5");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

interface IMetropolisRouter {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    
    // Mevcut fonksiyonlar
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

    // Yeni eklenen fonksiyonlar
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

interface IMetropolisFactory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

// Pair interface'ini de ekleyelim
interface IMetropolisPair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function sync() external;
}

// FARMER Token Contract
contract FARMER is ERC20, ReentrancyGuard, Ownable {
    // Constants
    uint256 private constant TOTAL_SUPPLY = 1_000_000 * 10**18;
    uint256 private constant TAX_RATE = 5; // 5%
    uint256 private constant LIQUIDITY_TAX = 25; // 2.5%
    uint256 private constant AIRDROP_TAX = 25; // 2.5%
    uint256 private constant MIN_HOLDER_AMOUNT = 10 * 10**18; // 10 tokens minimum for holder status
    uint256 private constant MIN_TOKENS_FOR_PROCESS = 100 * 10**18; // 100 tokens minimum for processing
    uint256 private constant SWAP_PERCENTAGE = 75; // 75% will be swapped
    uint256 private constant LIQUIDITY_PERCENTAGE = 25; // 25% will be used for liquidity
    uint256 private constant MAX_SLIPPAGE = 30; // 30% slippage tolerance

    // Metropolis DEX addresses
    IMetropolisRouter public metropolisRouter;
    IMetropolisFactory public metropolisFactory;
    address public sonicToken;
    address public liquidityPair;

    // Holder tracking
    mapping(address => bool) public isHolder;
    address[] public holders;

    // Optimize events
    event LiquidityAdded(uint256 indexed tokenAmount, uint256 indexed sonicAmount);
    event AirdropDistributed(uint256 indexed amount, uint256 indexed holdersCount);
    event SwapFailed(string indexed reason);
    event ProcessStarted(uint256 indexed tokensForLiquidity, uint256 indexed tokensForAirdrop);
    event SwapSuccessful(uint256 indexed tokensSwapped, uint256 indexed wethReceived);
    event PairReservesUpdated(uint256 indexed farmReserve, uint256 indexed wethReserve);
    event ContractInitialized(address indexed router, address indexed factory, address indexed sonic);

    uint256 private _pendingLiquidityTokens;
    uint256 private _pendingAirdropTokens;
    bool private _initialized;

    constructor() ERC20("FARMER", "FARM") Ownable(msg.sender) {
        address _metropolisRouter = 0x95a7e403d7cF20F675fF9273D66e94d35ba49fA3;
        address _metropolisFactory = 0x1570300e9cFEC66c9Fb0C8bc14366C86EB170Ad0;
        address _sonicToken = 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38;

        require(_metropolisRouter != address(0) && _metropolisFactory != address(0) && _sonicToken != address(0), "E1");

        metropolisRouter = IMetropolisRouter(_metropolisRouter);
        metropolisFactory = IMetropolisFactory(_metropolisFactory);
        sonicToken = _sonicToken;

        _mint(address(this), TOTAL_SUPPLY);
    }

    function initialize() external onlyOwner {
        require(!_initialized, "E1");
        _initialized = true;

        // Try to get existing pair first
        liquidityPair = metropolisFactory.getPair(address(this), sonicToken);
        
        // If pair doesn't exist, create it
        if (liquidityPair == address(0)) {
            liquidityPair = metropolisFactory.createPair(address(this), sonicToken);
        }
        
        require(liquidityPair != address(0), "E5");

        // Router için max onay
        _approve(address(this), address(metropolisRouter), type(uint256).max);
        
        // SONIC token için onaylar
        IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
        IERC20(sonicToken).approve(liquidityPair, type(uint256).max);
        
        // FARMER token için onaylar
        IERC20(address(this)).approve(liquidityPair, type(uint256).max);
        IERC20(address(this)).approve(address(metropolisRouter), type(uint256).max);

        emit ContractInitialized(address(metropolisRouter), address(metropolisFactory), sonicToken);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        // Boş implementasyon kaldırıldı
    }

    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        // Boş implementasyon kaldırıldı
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        require(from != address(0) && to != address(0), "E0");
        
        // Skip tax for owner and contract transfers
        if (from == owner() || to == owner() || from == address(this) || to == address(this) || !_initialized) {
            super._transfer(from, to, amount);
            _updateHolder(from);
            _updateHolder(to);
            return;
        }

        bool isSellOrBuy = to == liquidityPair || from == liquidityPair;
        if (isSellOrBuy) {
            // Calculate tax amount (5%)
            uint256 totalTax = (amount * TAX_RATE) / 100;
            uint256 transferAmount = amount - totalTax;
            
            // First transfer main amount to recipient
            super._transfer(from, to, transferAmount);
            
            // Then transfer tax to contract
            super._transfer(from, address(this), totalTax);

            // Split tax between liquidity and airdrop (2.5% each)
            _pendingLiquidityTokens += (totalTax * LIQUIDITY_TAX) / 100;  // 2.5% for liquidity
            _pendingAirdropTokens += (totalTax * AIRDROP_TAX) / 100;    // 2.5% for airdrop

            // Try to process if we have enough tokens
            if ((_pendingLiquidityTokens >= MIN_TOKENS_FOR_PROCESS || 
                _pendingAirdropTokens >= MIN_TOKENS_FOR_PROCESS) && 
                holders.length > 0) {
                // Refresh router approvals first
                _approve(address(this), address(metropolisRouter), type(uint256).max);
                IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
                
                // Then refresh pair approvals
                IERC20(sonicToken).approve(liquidityPair, type(uint256).max);
                IERC20(address(this)).approve(liquidityPair, type(uint256).max);
                
                try this.processLiquidityAndAirdrop() {
                    // Process successful
                } catch Error(string memory reason) {
                    emit SwapFailed(string(abi.encodePacked("Auto process failed: ", reason)));
                } catch {
                    emit SwapFailed("Unknown error in automatic processing");
                }
            }
        } else {
            // Normal transfer without tax
            super._transfer(from, to, amount);
        }
        
        // Update holder status for both addresses
        _updateHolder(from);
        _updateHolder(to);
    }

    function _updateHolder(address account) private {
        if (account != liquidityPair && account != address(this)) {
            uint256 balance = balanceOf(account);
            bool isCurrentlyHolder = isHolder[account];
            
            if (balance >= MIN_HOLDER_AMOUNT && !isCurrentlyHolder) {
                isHolder[account] = true;
                holders.push(account);
            } else if (balance < MIN_HOLDER_AMOUNT && isCurrentlyHolder) {
                isHolder[account] = false;
                _removeHolder(account);
            }
        }
    }

    function _removeHolder(address account) private {
        for (uint256 i = 0; i < holders.length; i++) {
            if (holders[i] == account) {
                holders[i] = holders[holders.length - 1];
                holders.pop();
                break;
            }
        }
    }

    function processLiquidityAndAirdrop() external nonReentrant {
        require(_pendingLiquidityTokens > 0 || _pendingAirdropTokens > 0, "E5");
        require(holders.length > 0, "E6");
        
        uint256 totalTokens = _pendingLiquidityTokens + _pendingAirdropTokens;
        require(totalTokens >= MIN_TOKENS_FOR_PROCESS, "E7");
        
        emit ProcessStarted(_pendingLiquidityTokens, _pendingAirdropTokens);

        // Reset pending amounts
        uint256 tempLiquidityTokens = _pendingLiquidityTokens;
        uint256 tempAirdropTokens = _pendingAirdropTokens;
        _pendingLiquidityTokens = 0;
        _pendingAirdropTokens = 0;

        // Önce tüm tokenleri SONIC'e çevir
        uint256 sonicReceived = _swapTokensForSonic(totalTokens);
        if (sonicReceived > 0) {
            // Likidite için SONIC ayır
            uint256 sonicForLiquidity = (sonicReceived * LIQUIDITY_PERCENTAGE) / 100;
            uint256 sonicForAirdrop = sonicReceived - sonicForLiquidity;

            // Likidite ekle
            if (sonicForLiquidity > 0) {
                _addLiquidityWithoutSlippage(tempLiquidityTokens, sonicForLiquidity);
            }

            // Airdrop dağıt
            if (sonicForAirdrop > 0) {
                _processAirdrop(sonicForAirdrop);
            }
        } else {
            // Swap başarısız olursa tokenleri geri ekle
            _pendingLiquidityTokens = tempLiquidityTokens;
            _pendingAirdropTokens = tempAirdropTokens;
        }
    }

    function _swapTokensForSonic(uint256 tokenAmount) private returns (uint256) {
        if (tokenAmount == 0) return 0;

        // Swap hesaplaması yapılıyor
        (bool success, uint256 expectedSonicOut, ) = _calculateSwapOutput(tokenAmount);
        if (!success || expectedSonicOut == 0) return 0;
        
        // Pair kontratına FARMER tokenları gönder
        super._transfer(address(this), address(metropolisRouter), tokenAmount);
        
        // Router'a onayları yenile
        _approve(address(this), address(metropolisRouter), tokenAmount);
        
        // Router üzerinden swap yap
        uint256 minAmountOut = expectedSonicOut * (100 - MAX_SLIPPAGE) / 100; // %30 slippage toleransı ile
        
        // Swap için path oluştur: FARMER -> SONIC
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = sonicToken;
        
        uint256 initialSonicBalance = IERC20(sonicToken).balanceOf(address(this));
        
        try metropolisRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
            tokenAmount,
            minAmountOut,
            path,
            address(this), // Direkt kontrata gönder
            block.timestamp + 300
        ) {
            // Swap başarılı oldu, alınan SONIC miktarını hesapla
            uint256 finalSonicBalance = IERC20(sonicToken).balanceOf(address(this));
            uint256 received = finalSonicBalance - initialSonicBalance;
            
            if (received > 0) {
                _emitSwapSuccess(tokenAmount, received);
                return received;
            } else {
                emit SwapFailed("No SONIC received after swap");
                return 0;
            }
        } catch Error(string memory reason) {
            emit SwapFailed(string(abi.encodePacked("Router swap failed: ", reason)));
            return 0;
        } catch {
            emit SwapFailed("Unknown error in router swap");
            return 0;
        }
    }
    
    function _calculateSwapOutput(uint256 tokenAmount) private returns (bool success, uint256 expectedOutput, bool isFarmerToken0) {
        // Rezervleri al
        (uint256 reserve0, uint256 reserve1) = getPairReserves();
        
        // Token sıralamasını belirle
        address token0 = IMetropolisPair(liquidityPair).token0();
        isFarmerToken0 = token0 == address(this);
        
        // Farmer ve SONIC için rezervleri ayarla
        uint256 farmerReserve = isFarmerToken0 ? reserve0 : reserve1;
        uint256 sonicReserve = isFarmerToken0 ? reserve1 : reserve0;
        
        if (farmerReserve == 0 || sonicReserve == 0) {
            emit SwapFailed("Insufficient pair reserves");
            return (false, 0, isFarmerToken0);
        }
        
        // Swap'tan beklenen çıktıyı hesapla (0.3% fee ile)
        uint256 amountInWithFee = tokenAmount * 997;
        uint256 numerator = amountInWithFee * sonicReserve;
        uint256 denominator = (farmerReserve * 1000) + amountInWithFee;
        expectedOutput = numerator / denominator;
        
        if (expectedOutput == 0) {
            emit SwapFailed("Calculated output amount is zero");
            return (false, 0, isFarmerToken0);
        }
        
        return (true, expectedOutput, isFarmerToken0);
    }
    
    // Event emit işlemini ayrı bir fonksiyona taşıyarak stack derinliğini azaltıyoruz
    function _emitSwapSuccess(uint256 amountIn, uint256 amountOut) private {
        emit SwapSuccessful(amountIn, amountOut);
    }

    function _addLiquidityWithoutSlippage(uint256 tokenAmount, uint256 sonicAmount) private {
        if (tokenAmount == 0 || sonicAmount == 0) return;

        // Onayları yenile
        _approve(address(this), address(metropolisRouter), tokenAmount);
        IERC20(sonicToken).approve(address(metropolisRouter), sonicAmount);

        try metropolisRouter.addLiquidity(
            address(this),
            sonicToken,
            tokenAmount,
            sonicAmount,
            0, // Minimum çıktıları 0 yaparak slippage'ı kaldırıyoruz
            0,
            address(this),
            block.timestamp + 300
        ) {
            emit LiquidityAdded(tokenAmount, sonicAmount);
        } catch Error(string memory reason) {
            emit SwapFailed(reason);
            _pendingLiquidityTokens += tokenAmount;
        } catch {
            emit SwapFailed("Unknown error in addLiquidity");
            _pendingLiquidityTokens += tokenAmount;
        }
    }

    function _processAirdrop(uint256 sonicAmount) private {
        if (sonicAmount == 0 || holders.length == 0) return;
        
        uint256 amountPerHolder = sonicAmount / holders.length;
        if (amountPerHolder == 0) return;

        for (uint256 i = 0; i < holders.length && i < 100; i++) {
            if (holders[i] != address(0)) {
                try IERC20(sonicToken).transfer(holders[i], amountPerHolder) {
                    // Transfer successful
                } catch {
                    continue;
                }
            }
        }
        
        emit AirdropDistributed(sonicAmount, holders.length);
    }

    // View functions
    function getHolderCount() external view returns (uint256) {
        return holders.length;
    }
    
    function getHolders() external view returns (address[] memory) {
        return holders;
    }

    // Initial liquidity function (must be called by owner with ETH)
    function addInitialLiquidity(uint256 tokenAmount) external payable onlyOwner {
        require(msg.value > 0, "E8");
        require(tokenAmount > 0, "E9");
        
        require(
            IERC20(address(this)).balanceOf(address(this)) >= tokenAmount,
            "Insufficient token balance in contract"
        );

        _approve(address(this), address(metropolisRouter), tokenAmount);

        try metropolisRouter.addLiquidityETH{value: msg.value}(
            address(this),
            tokenAmount,
            0,
            0,
            msg.sender,
            block.timestamp
        ) {
            emit LiquidityAdded(tokenAmount, msg.value);
        } catch {
            _approve(address(this), address(metropolisRouter), 0);
            revert("Failed to add liquidity");
        }

        uint256 remainingETH = address(this).balance;
        if (remainingETH > 0) {
            payable(msg.sender).transfer(remainingETH);
        }
    }

    function setRouter(address _router) external onlyOwner {
        require(_router != address(0), "E11");
        metropolisRouter = IMetropolisRouter(_router);
    }

    function rescueTokens(address _token, uint256 _amount) external onlyOwner {
        require(_token != address(this), "Cannot rescue FARMER tokens");
        IERC20(_token).transfer(owner(), _amount);
    }

    // Transfer tokens to owner
    function withdrawTokensToOwner(uint256 amount) external onlyOwner {
        require(
            IERC20(address(this)).balanceOf(address(this)) >= amount,
            "Insufficient balance"
        );
        _transfer(address(this), msg.sender, amount);
    }

    // View functions for pending amounts
    function getPendingLiquidityTokens() external view returns (uint256) {
        return _pendingLiquidityTokens;
    }

    function getPendingAirdropTokens() external view returns (uint256) {
        return _pendingAirdropTokens;
    }

    // Manual trigger for processing (only owner)
    function triggerProcessing() external onlyOwner {
        require(_pendingLiquidityTokens > 0 || _pendingAirdropTokens > 0, "E5");
        require(holders.length > 0, "E6");
        try this.processLiquidityAndAirdrop() {
            // Process successful
        } catch {
            emit ProcessStarted(_pendingLiquidityTokens, _pendingAirdropTokens);
        }
    }

    function checkAndRefreshAllowances() external onlyOwner {
        uint256 farmAllowance = IERC20(address(this)).allowance(address(this), address(metropolisRouter));
        if (farmAllowance < TOTAL_SUPPLY) {
            _approve(address(this), address(metropolisRouter), TOTAL_SUPPLY);
        }

        uint256 wethBalance = IERC20(sonicToken).balanceOf(address(this));
        if (wethBalance > 0) {
            uint256 wethAllowance = IERC20(sonicToken).allowance(address(this), address(metropolisRouter));
            if (wethAllowance < wethBalance) {
                IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
            }
        }
    }

    // Debug function
    function getSwapInfo() public view returns (uint256, uint256, bool, address) {
        return (
            balanceOf(address(this)),
            IERC20(sonicToken).allowance(address(this), address(metropolisRouter)),
            liquidityPair != address(0),
            liquidityPair
        );
    }

    function getPairReserves() public view returns (uint256 farmReserve, uint256 wethReserve) {
        (uint112 reserve0, uint112 reserve1,) = IMetropolisPair(liquidityPair).getReserves();
        address token0 = IMetropolisPair(liquidityPair).token0();
        if (token0 == address(this)) {
            return (uint256(reserve0), uint256(reserve1));
        }
        return (uint256(reserve1), uint256(reserve0));
    }

    function getMinimumOutputWithSlippage(uint256 amountIn) public view returns (uint256) {
        (uint256 farmReserve, uint256 wethReserve) = getPairReserves();
        if (farmReserve == 0 || wethReserve == 0) return 0;
        
        uint256 amountInWithFee = amountIn * 997; // 0.3% fee
        uint256 numerator = amountInWithFee * wethReserve;
        uint256 denominator = (farmReserve * 1000) + amountInWithFee;
        uint256 amountOut = numerator / denominator;
        
        // Apply slippage tolerance (30%)
        return amountOut * (100 - MAX_SLIPPAGE) / 100;
    }

    // aprov all
    function refreshAllApprovals() external onlyOwner {
        _approve(address(this), address(metropolisRouter), type(uint256).max);
        IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
        
        try IERC20(sonicToken).approve(liquidityPair, type(uint256).max) {} catch {}
        try IERC20(address(this)).approve(liquidityPair, type(uint256).max) {} catch {}
    }

    receive() external payable {}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):