S Price: $0.583877 (-2.19%)

Contract Diff Checker

Contract Name:
FARMER

Contract Source Code:

File 1 of 1 : FARMER

/**
 *Submitted for verification at SonicScan.org on 2025-03-02
*/

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

// 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.
 */
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), "E1");
        _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);
        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;
}

// 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
    uint256 private constant TREASURY_PERCENTAGE = 25; // 25% of Sonic tokens to treasury
    uint256 private constant HOLDERS_PERCENTAGE = 75; // 75% of Sonic tokens to holders

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

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

    // Events
    event LiquidityAdded(uint256 tokenAmount, uint256 sonicAmount);
    event AirdropDistributed(uint256 amount, uint256 holdersCount);
    event TreasuryTransfer(uint256 amount);
    event SwapFailed(string reason);
    event ProcessStarted(uint256 tokensForLiquidity, uint256 tokensForAirdrop);
    event SwapSuccessful(uint256 tokensSwapped, uint256 wethReceived);
    event TreasuryWalletUpdated(address oldTreasury, address newTreasury);
    event LiquidityAddFailed(string reason);
    event AirdropFailed(string reason);
    event PairReservesUpdated(uint256 farmReserve, uint256 wethReserve);
    event ApprovalRefreshed(address token, address spender, uint256 amount);

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

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

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

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

        _mint(address(this), TOTAL_SUPPLY);
    }

    function initialize() external onlyOwner {
        require(!_initialized, "F2");
        _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), "F3");

        _approve(address(this), address(metropolisRouter), type(uint256).max);
        
        require(IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max), "F4");
        IERC20(sonicToken).approve(liquidityPair, type(uint256).max);
        IERC20(address(this)).approve(liquidityPair, type(uint256).max);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);
    }

    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        super._afterTokenTransfer(from, to, amount);
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        // Vergi işleme mantığı
        if (
            !_inSwap && 
            from != owner() && 
            to != owner() && 
            from != address(this) && 
            to == liquidityPair
        ) {
            // Vergi hesapla
            uint256 taxAmount = amount * TAX_RATE / 100;
            
            if (taxAmount > 0) {
                // Vergiyi likidite ve airdrop için ayır
                uint256 liquidityTokens = taxAmount * LIQUIDITY_TAX / 100;
                uint256 airdropTokens = taxAmount * AIRDROP_TAX / 100;
                
                // Vergi miktarını ana miktardan düş
                uint256 transferAmount = amount - taxAmount;
                
                // Vergiyi kontrata aktar
                super._transfer(from, address(this), taxAmount);
                
                // Kalan miktarı alıcıya aktar
                super._transfer(from, to, transferAmount);
                
                // Bekleyen miktarları güncelle
                _pendingLiquidityTokens += liquidityTokens;
                _pendingAirdropTokens += airdropTokens;
                
                // Eğer yeterli miktarda token biriktiysek işlemi başlat
                if (_pendingLiquidityTokens + _pendingAirdropTokens >= MIN_TOKENS_FOR_PROCESS) {
                    try this.processLiquidityAndAirdrop() {} catch {}
                }
                
                // Holder durumunu güncelle
                _updateHolder(from, balanceOf(from) >= MIN_HOLDER_AMOUNT);
                _updateHolder(to, balanceOf(to) >= MIN_HOLDER_AMOUNT);
                
                return;
            }
        }
        
        // Normal transfer
        super._transfer(from, to, amount);
        
        // Holder durumunu güncelle
        _updateHolder(from, balanceOf(from) >= MIN_HOLDER_AMOUNT);
        _updateHolder(to, balanceOf(to) >= MIN_HOLDER_AMOUNT);
    }

    function _updateHolder(address account, bool isHolderStatus) private {
        if (account != liquidityPair && account != address(this)) {
            if (isHolderStatus && !isHolder[account]) {
                isHolder[account] = true;
                holders.push(account);
            } else if (!isHolderStatus && isHolder[account]) {
                isHolder[account] = false;
                
                // Remove from holders array
                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(!_inSwap, "Already processing");
        _inSwap = true;
        
        uint256 tokensForLiquidity = _pendingLiquidityTokens;
        uint256 tokensForAirdrop = _pendingAirdropTokens;
        
        if (tokensForLiquidity == 0 && tokensForAirdrop == 0) {
            _inSwap = false;
            return;
        }
        
        emit ProcessStarted(tokensForLiquidity, tokensForAirdrop);
        
        // Reset pending amounts
        _pendingLiquidityTokens = 0;
        _pendingAirdropTokens = 0;
        
        // Refresh approvals
        _approve(address(this), address(metropolisRouter), type(uint256).max);
        IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
        
        // Process swap
        uint256 totalTokensToSwap = tokensForLiquidity + tokensForAirdrop;
        uint256 sonicReceived = _processSwap(totalTokensToSwap);
        
        if (sonicReceived == 0) {
            _inSwap = false;
            return;
        }
        
        // Calculate amounts
        uint256 sonicForLiquidity = sonicReceived * tokensForLiquidity / totalTokensToSwap;
        uint256 sonicForAirdrop = sonicReceived - sonicForLiquidity;
        
        // Process liquidity
        if (sonicForLiquidity > 0) {
            _processLiquidity(tokensForLiquidity, sonicForLiquidity);
        }
        
        // Process airdrop
        if (sonicForAirdrop > 0) {
            uint256 sonicForTreasury = sonicForAirdrop * TREASURY_PERCENTAGE / 100;
            uint256 sonicForHolders = sonicForAirdrop - sonicForTreasury;
            
            _processTreasuryTransfer(sonicForTreasury);
            _processAirdrop(sonicForHolders);
        }
        
        _inSwap = false;
    }

    function _processSwap(uint256 tokensToSwap) private returns (uint256) {
        if (tokensToSwap == 0) return 0;

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

        // Swap için path oluştur
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = sonicToken;

        uint256 sonicBefore = IERC20(sonicToken).balanceOf(address(this));

        try metropolisRouter.swapExactTokensForTokens(
            tokensToSwap,
            0,
            path,
            address(this),
            block.timestamp + 300
        ) {
            uint256 sonicAfter = IERC20(sonicToken).balanceOf(address(this));
            uint256 sonicReceived = sonicAfter - sonicBefore;
            emit SwapSuccessful(tokensToSwap, sonicReceived);
            return sonicReceived;
        } catch Error(string memory reason) {
            emit SwapFailed(reason);
            return 0;
        } catch {
            emit SwapFailed("Hata");
            return 0;
        }
    }

    function _processLiquidity(uint256 tokensForLiquidity, uint256 sonicForLiquidity) private {
        if (tokensForLiquidity == 0 || sonicForLiquidity == 0) {
            return;
        }

        // Approve Sonic token for router
        IERC20(sonicToken).approve(address(metropolisRouter), sonicForLiquidity);
        // Approve this token for router
        _approve(address(this), address(metropolisRouter), tokensForLiquidity);

        try metropolisRouter.addLiquidity(
            address(this),
            sonicToken,
            tokensForLiquidity,
            sonicForLiquidity,
            tokensForLiquidity * (100 - MAX_SLIPPAGE) / 100,
            sonicForLiquidity * (100 - MAX_SLIPPAGE) / 100,
            address(this),
            block.timestamp + 300
        ) {
            emit LiquidityAdded(tokensForLiquidity, sonicForLiquidity);
        } catch Error(string memory reason) {
            emit LiquidityAddFailed(reason);
        } catch {
            emit LiquidityAddFailed("Hata");
        }
    }

    function _processTreasuryTransfer(uint256 sonicAmount) private {
        if (sonicAmount == 0 || treasuryWallet == address(0)) return;
        
        try IERC20(sonicToken).transfer(treasuryWallet, sonicAmount) {
            emit TreasuryTransfer(sonicAmount);
        } catch {
            emit AirdropFailed("Treasury transfer failed");
        }
    }

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

        uint256 sonicPerHolder = sonicAmount / holders.length;
        
        for (uint256 i = 0; i < holders.length; i++) {
            if (holders[i] != address(0) && holders[i] != address(this) && holders[i] != liquidityPair) {
                try IERC20(sonicToken).transfer(holders[i], sonicPerHolder) {
                    // Transfer başarılı
                } catch Error(string memory reason) {
                    emit AirdropFailed(reason);
                } catch {
                    emit AirdropFailed("Hata");
                }
            }
        }
    }

    // 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, "Must provide ETH for initial liquidity");
        require(tokenAmount > 0, "Must provide token amount for initial liquidity");
        
        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), "Invalid router address");
        metropolisRouter = IMetropolisRouter(_router);
    }

    function rescueTokens(address _token, uint256 _amount) external onlyOwner {
        require(_token != address(this), "Cannot rescue FARMER tokens");
        IERC20(_token).transfer(owner(), _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, "No pending tokens");
        require(holders.length > 0, "No holders");
        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() external view returns (
        uint256 contractBalance,
        uint256 routerAllowance,
        bool pairExists,
        address pair,
        uint256 pendingLiq,
        uint256 pendingAirdrop
    ) {
        contractBalance = IERC20(address(this)).balanceOf(address(this));
        routerAllowance = IERC20(address(this)).allowance(address(this), address(metropolisRouter));
        pair = IMetropolisFactory(metropolisRouter.factory()).getPair(address(this), sonicToken);
        pairExists = pair != address(0);
        pendingLiq = _pendingLiquidityTokens;
        pendingAirdrop = _pendingAirdropTokens;
    }

    // Pair rezervlerini kontrol et
    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));
    }

    // Swap için minimum çıktı miktarını hesapla
    function getMinimumOutput(uint256 amountIn) public view returns (uint256) {
        (uint256 farmReserve, uint256 wethReserve) = getPairReserves();
        if (farmReserve == 0 || wethReserve == 0) return 0;
        
        uint256 amountInWithFee = amountIn * 997; // %0.3 işlem ücreti
        uint256 numerator = amountInWithFee * wethReserve;
        uint256 denominator = (farmReserve * 1000) + amountInWithFee;
        return numerator / denominator;
    }

    // Router için onayları yenile
    function refreshAllApprovals() external onlyOwner {
        // Router için onayları yenile
        _approve(address(this), address(metropolisRouter), type(uint256).max);
        
        // Sonic token için onayları yenile
        try IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max) {
            emit ApprovalRefreshed(sonicToken, address(metropolisRouter), type(uint256).max);
        } catch {}
    }
    
    // Likidite çifti için onayları yenile (ayrı bir fonksiyon olarak)
    function refreshPairApprovals() external onlyOwner {
        if (liquidityPair != address(0)) {
            try IERC20(sonicToken).approve(liquidityPair, type(uint256).max) {
                emit ApprovalRefreshed(sonicToken, liquidityPair, type(uint256).max);
            } catch {}
            
            try IERC20(address(this)).approve(liquidityPair, type(uint256).max) {
                emit ApprovalRefreshed(address(this), liquidityPair, type(uint256).max);
            } catch {}
        }
    }

    // Set treasury wallet (only owner)
    function setTreasuryWallet(address _treasuryWallet) external onlyOwner {
        require(_treasuryWallet != address(0), "Invalid treasury address");
        address oldTreasury = treasuryWallet;
        treasuryWallet = _treasuryWallet;
        emit TreasuryWalletUpdated(oldTreasury, _treasuryWallet);
    }

    receive() external payable {}
}

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

Context size (optional):