S Price: $0.77321 (-4.26%)

Contract Diff Checker

Contract Name:
TEST

Contract Source Code:

File 1 of 1 : TEST

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

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }
}

contract Ownable is Context {
    address private _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor() { _owner = _msgSender(); emit OwnershipTransferred(address(0), _owner); }
    function owner() public view returns (address) { return _owner; }
    modifier onlyOwner() { require(_msgSender() == _owner, "Not owner"); _; }
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0), "Zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, 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 sender,address recipient,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);
}

contract ERC20 is Context, IERC20 {
    mapping(address => uint256) internal _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 internal _totalSupply;
    string private _name;
    string private _symbol;
    constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; }
    function name() public view returns(string memory){ return _name; }
    function symbol() public view returns(string memory){ return _symbol; }
    function decimals() public pure returns(uint8){ return 18; }
    function totalSupply() public view override returns(uint256){ return _totalSupply; }
    function balanceOf(address account) public view override returns(uint256){ return _balances[account]; }
    function transfer(address recipient, uint256 amount) public override returns(bool){
        _transfer(_msgSender(), recipient, amount);
        return true;
    }
    function allowance(address owner, address spender) public view override returns(uint256){
        return _allowances[owner][spender];
    }
    function approve(address spender, uint256 amount) public override returns(bool){
        _approve(_msgSender(), spender, amount);
        return true;
    }
    function transferFrom(address sender, address recipient, uint256 amount) public override returns(bool){
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()] - amount);
        return true;
    }
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0) && recipient != address(0), "Zero address");
        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "Insufficient balance");
        unchecked { _balances[sender] = senderBalance - amount; }
        _balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "Mint to zero");
        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0) && spender != address(0), "Zero address");
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
}

interface ImetropolisV2Factory {
    function createPair(address tokenA, address tokenB) external returns (address pair);
}
interface ImetropolisV2Router02 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
         uint256 tokenAmount, uint256 minETH, address[] calldata path, address to, uint256 deadline
    ) external;
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
         uint256 tokenAmount, uint256 minTokens, address[] calldata path, address to, uint256 deadline
    ) external;
}

contract TEST is ERC20, Ownable {
    ImetropolisV2Router02 public metropolisV2Router;
    address public metropolisV2Pair;
    address public marketingWallet;
    address public rewardToken; // e.g., wS token address; update before deployment
    uint256 public maxWallet;
    uint256 public swapTokensAtAmount;
    bool private swapping;
    
    // Fee structure in basis points (out of 1000)
    uint256 public rewardsFeeBuy;
    uint256 public marketingFeeBuy;
    uint256 public rewardsFeeSell;
    uint256 public marketingFeeSell;
    uint256 public totalBuyFees;
    uint256 public totalSellFees;
    
    // Dividend tracking (dividends in rewardToken)
    uint256 public magnifiedDividendPerShare;
    mapping(address => int256) public magnifiedDividendCorrections;
    mapping(address => uint256) public withdrawnDividends;
    uint256 constant internal magnitude = 2**128;
    
    event DividendClaimed(address indexed account, uint256 amount);
    
    constructor() ERC20("TEST1", "TEST") {
        uint256 totalSupply = 1e6 * 1e18;
        _mint(msg.sender, totalSupply);
        maxWallet = totalSupply * 2 / 100;         // 2% max wallet
        swapTokensAtAmount = totalSupply * 2 / 1000; // 0.2% threshold
        
        // Set fee percentages (basis points: 30 = 3.0%)
        rewardsFeeBuy = 30;
        marketingFeeBuy = 20;
        totalBuyFees = rewardsFeeBuy + marketingFeeBuy;
        rewardsFeeSell = 30;
        marketingFeeSell = 20;
        totalSellFees = rewardsFeeSell + marketingFeeSell;
        
        marketingWallet = msg.sender; // deployer wallet receives marketing ETH
        rewardToken = 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38; // <-- Set your reward token (wS) address here
        
        // Initialize router and create pair (update router address for your network)
        metropolisV2Router = ImetropolisV2Router02(0x95a7e403d7cF20F675fF9273D66e94d35ba49fA3);
        metropolisV2Pair = ImetropolisV2Factory(metropolisV2Router.factory()).createPair(address(this), metropolisV2Router.WETH());
    }
    
    // Trading is always enabled.
    // Override _transfer to enforce max wallet and deduct fees on buys/sells.
    function _transfer(address from, address to, uint256 amount) internal override {
        if (to != metropolisV2Pair && to != owner()) {
            require(balanceOf(to) + amount <= maxWallet, "Exceeds max wallet");
        }
        
        uint256 fees = 0;
        if (!swapping && from != owner() && to != owner()) {
            if (from == metropolisV2Pair) { // Buy transaction
                fees = amount * totalBuyFees / 1000;
            } else if (to == metropolisV2Pair) { // Sell transaction
                fees = amount * totalSellFees / 1000;
            }
        }
        
        if (fees > 0) {
            super._transfer(from, address(this), fees);
            amount -= fees;
        }
        super._transfer(from, to, amount);
        
        // Update dividend correction for simple dividend tracking.
        int256 correction = int256(magnifiedDividendPerShare * amount);
        magnifiedDividendCorrections[from] += correction;
        magnifiedDividendCorrections[to] -= correction;
        
        // If not in a swap and threshold met on non-buy, process swap.
        if (!swapping && balanceOf(address(this)) >= swapTokensAtAmount && from != metropolisV2Pair) {
            swapBack();
        }
    }
    
    // Swap collected fee tokens:
    // - Swap marketing portion for ETH and send to marketing wallet.
    // - Swap rewards portion for rewardToken and distribute as dividends.
    function swapBack() private {
        swapping = true;
        uint256 contractBalance = balanceOf(address(this));
        uint256 totalFeePortion = totalBuyFees + totalSellFees;
        uint256 rewardsPortion = contractBalance * (rewardsFeeBuy + rewardsFeeSell) / totalFeePortion;
        uint256 marketingPortion = contractBalance - rewardsPortion;
        
        swapTokensForEth(marketingPortion);
        (bool sent, ) = marketingWallet.call{value: address(this).balance}("");
        require(sent, "ETH transfer failed");
        
        uint256 initialRewardBalance = IERC20(rewardToken).balanceOf(address(this));
        swapTokensForReward(rewardsPortion);
        uint256 newRewardBalance = IERC20(rewardToken).balanceOf(address(this)) - initialRewardBalance;
        if (newRewardBalance > 0) {
            distributeSDividends(newRewardBalance);
        }
        swapping = false;
    }
    
    function swapTokensForEth(uint256 tokenAmount) private {
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = metropolisV2Router.WETH();
        _approve(address(this), address(metropolisV2Router), tokenAmount);
        metropolisV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount, 0, path, address(this), block.timestamp
        );
    }
    
    function swapTokensForReward(uint256 tokenAmount) private {
        address[] memory path = new address[](3);
        path[0] = address(this);
        path[1] = metropolisV2Router.WETH();
        path[2] = rewardToken;
        _approve(address(this), address(metropolisV2Router), tokenAmount);
        metropolisV2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
            tokenAmount, 0, path, address(this), block.timestamp
        );
    }
    
    // Increase per-token dividend amount.
    function distributeSDividends(uint256 amount) internal {
        if (_totalSupply > 0) {
            magnifiedDividendPerShare += amount * magnitude / _totalSupply;
        }
    }
    
    // View function for withdrawable dividend of an account.
    function withdrawableSDividendOf(address account) public view returns (uint256) {
        int256 accumulated = int256(balanceOf(account)) * int256(magnifiedDividendPerShare) + magnifiedDividendCorrections[account];
        uint256 totalAccumulated = accumulated < 0 ? 0 : uint256(accumulated);
        return totalAccumulated - withdrawnDividends[account];
    }
    
    // Claim dividends (rewardToken) for the caller; gas paid by caller.
    function claimSDividend() external {
        uint256 dividend = withdrawableSDividendOf(msg.sender);
        require(dividend > 0, "No dividend");
        withdrawnDividends[msg.sender] += dividend;
        IERC20(rewardToken).transfer(msg.sender, dividend);
        emit DividendClaimed(msg.sender, dividend);
    }
    
    receive() external payable { }
}

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

Context size (optional):