S Price: $0.595116 (+5.69%)

Contract Diff Checker

Contract Name:
FARMER

Contract Source Code:

File 1 of 1 : FARMER

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

// 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, "ReentrancyGuard: reentrant call");
        _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("Ownable: new owner is the zero address");
        }
        _transferOwnership(initialOwner);
    }

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

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

    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _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), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");
        _beforeTokenTransfer(from, to, amount);
        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        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), "ERC20: mint to the zero address");
        _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), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");
        _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, "ERC20: insufficient allowance");
            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);
    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);
}

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

// FARMER Token Contract
contract FARMER is ERC20, ReentrancyGuard, Ownable {
    // Constants
    uint256 public constant TOTAL_SUPPLY = 1_000_000 * 10**18;
    uint256 public constant TAX_RATE = 5; // 5%
    uint256 public constant LIQUIDITY_TAX = 25; // 2.5%
    uint256 public constant AIRDROP_TAX = 25; // 2.5%
    uint256 public constant MIN_HOLDER_AMOUNT = 10 * 10**18; // 10 tokens
    uint256 public constant MIN_TOKENS_FOR_PROCESS = 100 * 10**18; // 100 token minimum for both operations

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

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

    // Events
    event LiquidityAdded(uint256 tokenAmount, uint256 sonicAmount);
    event AirdropDistributed(uint256 amount, uint256 holdersCount);
    event SwapFailed(string reason);
    event LiquidityAddFailed(string reason);
    event AirdropFailed(string reason);
    event ProcessStarted(uint256 tokensForLiquidity, uint256 tokensForAirdrop);
    event SwapSuccessful(uint256 tokensSwapped, uint256 wethReceived);

    uint256 private _pendingLiquidityTokens;
    uint256 private _pendingAirdropTokens;

    constructor() ERC20("FARMER", "FARM") Ownable(msg.sender) {
        metropolisRouter = IMetropolisRouter(0x95a7e403d7cF20F675fF9273D66e94d35ba49fA3);
        metropolisFactory = IMetropolisFactory(0x1570300e9cFEC66c9Fb0C8bc14366C86EB170Ad0);
        sonicToken = 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38; // Doğru WETH adresi

        // Mint all tokens to contract first
        _mint(address(this), TOTAL_SUPPLY);
        
        // Create pair
        liquidityPair = metropolisFactory.createPair(address(this), sonicToken);
        
        // Approve router for full supply
        _approve(address(this), address(metropolisRouter), TOTAL_SUPPLY);
    }

    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 {
        if (from == owner() || to == owner() || from == address(this) || to == address(this)) {
            super._transfer(from, to, amount);
            _updateHolder(from);
            _updateHolder(to);
        } else {
            bool isSellOrBuy = to == liquidityPair || from == liquidityPair;
            
            if (isSellOrBuy) {
                uint256 totalTax = (amount * TAX_RATE) / 100;  // %5
                uint256 liquidityTax = (amount * LIQUIDITY_TAX) / 1000;  // %2.5 (25/1000)
                uint256 airdropTax = (amount * AIRDROP_TAX) / 1000;     // %2.5 (25/1000)
                uint256 transferAmount = amount - totalTax;
                
                // Transfer the tax to contract
                super._transfer(from, address(this), totalTax);
                // Transfer the remaining amount
                super._transfer(from, to, transferAmount);

                // Accumulate tokens for liquidity and airdrop
                _pendingLiquidityTokens += liquidityTax;
                _pendingAirdropTokens += airdropTax;

                // Process when either liquidity or airdrop tokens reach minimum
                if ((_pendingLiquidityTokens >= MIN_TOKENS_FOR_PROCESS || _pendingAirdropTokens >= MIN_TOKENS_FOR_PROCESS) && 
                    holders.length > 0) {
                    _processLiquidityAndAirdrop();
                }
            } else {
                super._transfer(from, to, amount);
            }
            
            _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 _processSwap(uint256 totalTokens) private returns (uint256) {
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = sonicToken;  // metropolisRouter.WETH() yerine sonicToken kullanıyoruz

        // Router onayını kontrol et
        uint256 currentAllowance = IERC20(address(this)).allowance(address(this), address(metropolisRouter));
        if (currentAllowance < totalTokens) {
            _approve(address(this), address(metropolisRouter), 0);
            _approve(address(this), address(metropolisRouter), type(uint256).max);
        }

        try metropolisRouter.swapExactTokensForTokens(
            totalTokens,
            0,  // minimum çıktı miktarı
            path,
            address(this),  // WETH'leri kontrata gönder
            block.timestamp + 300
        ) returns (uint[] memory) {
            uint256 wethBalance = IERC20(sonicToken).balanceOf(address(this));
            emit SwapSuccessful(totalTokens, wethBalance);
            return wethBalance;
        } catch Error(string memory reason) {
            emit SwapFailed(reason);
            return 0;
        } catch {
            emit SwapFailed("Unknown error in swap");
            return 0;
        }
    }

    function _processLiquidity(uint256 tokensForLiquidity, uint256 wethForLiquidity) private {
        if (wethForLiquidity > 0) {
            uint256 wethAllowance = IERC20(sonicToken).allowance(address(this), address(metropolisRouter));
            if (wethAllowance < wethForLiquidity) {
                IERC20(sonicToken).approve(address(metropolisRouter), type(uint256).max);
            }
            
            try metropolisRouter.addLiquidity(
                address(this),
                sonicToken,
                tokensForLiquidity / 2,
                wethForLiquidity,
                0,
                0,
                address(this),
                block.timestamp
            ) {
                emit LiquidityAdded(tokensForLiquidity / 2, wethForLiquidity);
            } catch Error(string memory reason) {
                emit LiquidityAddFailed(reason);
                _pendingLiquidityTokens = tokensForLiquidity;
            } catch {
                emit LiquidityAddFailed("Unknown error in addLiquidity");
                _pendingLiquidityTokens = tokensForLiquidity;
            }
        }
    }

    function _processAirdrop(uint256 wethForAirdrop) private {
        if (wethForAirdrop > 0 && holders.length > 0) {
            uint256 amountPerHolder = wethForAirdrop / holders.length;
            
            if (amountPerHolder > 0) {
                for (uint256 i = 0; i < holders.length && i < 100; i++) {
                    try IERC20(sonicToken).transfer(holders[i], amountPerHolder) {
                        // Transfer successful
                    } catch Error(string memory reason) {
                        emit AirdropFailed(reason);
                        continue;
                    } catch {
                        emit AirdropFailed("Unknown error in WETH transfer");
                        continue;
                    }
                }
                
                emit AirdropDistributed(wethForAirdrop, holders.length);
            }
        }
    }

    function _processLiquidityAndAirdrop() private {
        uint256 tokensForLiquidity = _pendingLiquidityTokens;
        uint256 tokensForAirdrop = _pendingAirdropTokens;
        uint256 totalTokens = tokensForLiquidity + tokensForAirdrop;
        
        emit ProcessStarted(tokensForLiquidity, tokensForAirdrop);

        // Önce kontrat bakiyesini kontrol et
        uint256 contractBalance = IERC20(address(this)).balanceOf(address(this));
        require(contractBalance >= totalTokens, "Insufficient token balance for swap");

        _pendingLiquidityTokens = 0;
        _pendingAirdropTokens = 0;
        
        // Router approval kontrolü
        uint256 currentAllowance = IERC20(address(this)).allowance(address(this), address(metropolisRouter));
        if (currentAllowance < totalTokens) {
            _approve(address(this), address(metropolisRouter), 0);
            _approve(address(this), address(metropolisRouter), TOTAL_SUPPLY);
        }

        // Likidite havuzu kontrolü
        address pair = IMetropolisFactory(metropolisRouter.factory()).getPair(address(this), metropolisRouter.WETH());
        require(pair != address(0), "Liquidity pair does not exist");
        require(pair == liquidityPair, "Invalid liquidity pair");

        // Process swap
        uint256 wethBalance = _processSwap(totalTokens);
        if (wethBalance > 0) {
            // Calculate proportions
            uint256 wethForLiquidity = (wethBalance * tokensForLiquidity) / totalTokens;
            uint256 wethForAirdrop = wethBalance - wethForLiquidity;

            // Process liquidity
            _processLiquidity(tokensForLiquidity, wethForLiquidity);

            // Process airdrop
            _processAirdrop(wethForAirdrop);
        } else {
            // If swap failed, restore pending amounts
            _pendingLiquidityTokens = tokensForLiquidity;
            _pendingAirdropTokens = tokensForAirdrop;
        }
    }

    // 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");
        
        // Check contract balance
        require(
            IERC20(address(this)).balanceOf(address(this)) >= tokenAmount,
            "Insufficient token balance in contract"
        );

        // Approve router to spend tokens directly from contract
        _approve(address(this), address(metropolisRouter), tokenAmount);

        // Add liquidity with minimal checks
        try metropolisRouter.addLiquidityETH{value: msg.value}(
            address(this),
            tokenAmount,
            0,              // No minimum token amount
            0,              // No minimum ETH amount
            msg.sender,     // LP tokens will go to owner directly
            block.timestamp // Immediate execution
        ) {
            emit LiquidityAdded(tokenAmount, msg.value);
        } catch {
            // If failed, revert the approval
            _approve(address(this), address(metropolisRouter), 0);
            revert("Failed to add liquidity");
        }

        // Return any unused ETH
        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);
    }

    // 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;
    }

    // Process liquidity and airdrop manually if needed
    function processLiquidityAndAirdrop() external onlyOwner {
        require(_pendingLiquidityTokens > 0 || _pendingAirdropTokens > 0, "No pending tokens");
        require(holders.length > 0, "No holders");
        _processLiquidityAndAirdrop();
    }

    function checkAndRefreshAllowances() external onlyOwner {
        // Check and refresh FARM approval for router
        uint256 farmAllowance = IERC20(address(this)).allowance(address(this), address(metropolisRouter));
        if (farmAllowance < TOTAL_SUPPLY) {
            _approve(address(this), address(metropolisRouter), TOTAL_SUPPLY);
        }

        // Check and refresh WETH approval for router
        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;
    }

    receive() external payable {}
}

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

Context size (optional):