ModernTetherToken

Description:

ERC20 token contract. Standard implementation for fungible tokens on Ethereum.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

/**
 * @title ModernTetherToken
 * @dev Simplified implementation of the Tether token with modern security features
 */
contract ModernTetherToken {
    // Events
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
    event Paused(address account);
    event Unpaused(address account);
    event BlacklistUpdated(address indexed account, bool isBlacklisted);
    event TokensIssued(address indexed to, uint256 amount);
    event TokensRedeemed(address indexed from, uint256 amount);
    event FeeParametersChanged(uint256 basisPointsRate, uint256 maximumFee);

    // Token metadata
    string private _name;
    string private _symbol;
    uint8 private constant _decimals = 6;
    uint256 private _totalSupply;

    // Role definitions
    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
    bytes32 public constant CONTROLLER_ROLE = keccak256("CONTROLLER_ROLE"); // Combined role for multiple functions

    // Role storage
    mapping(bytes32 => mapping(address => bool)) private _roles;

    // Fee structure
    uint256 public basisPointsRate;
    uint256 public maximumFee;

    // Blacklist functionality
    mapping(address => bool) public isBlackListed;

    // Pause state
    bool private _paused;

    // Balances and allowances
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

    /**
     * @dev Modifier to restrict function to role holders.
     */
    modifier onlyRole(bytes32 role) {
        require(hasRole(role, msg.sender), "Caller doesn't have required role");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Contract is paused");
        _;
    }

    /**
     * @dev Constructor
     * @param name_ The name of the token
     * @param symbol_ The symbol of the token
     * @param initialSupply The initial supply of tokens
     * @param admin The address that will have admin role
     */
    constructor(
        string memory name_,
        string memory symbol_,
        uint256 initialSupply,
        address admin
    ) {
        _name = name_;
        _symbol = symbol_;

        // Setup roles
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(CONTROLLER_ROLE, admin);

        // Mint initial supply
        _mint(admin, initialSupply);

        // Set default fee parameters
        basisPointsRate = 0;
        maximumFee = 0;
    }

    /**
     * @dev Returns basic token information and state
     */
    function getTokenInfo() public view returns (
        string memory name,
        string memory symbol,
        uint8 decimals,
        uint256 totalSupply,
        bool isPaused,
        uint256 feeRate,
        uint256 maxFee
    ) {
        return (
            _name,
            _symbol,
            _decimals,
            _totalSupply,
            _paused,
            basisPointsRate,
            maximumFee
        );
    }

    /**
     * @dev Returns the balance of a specific account.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev Returns the remaining allowance of spender over owner's tokens.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev Checks if an account has a specific role.
     */
    function hasRole(bytes32 role, address account) public view returns (bool) {
        return _roles[role][account];
    }

    /**
     * @dev Admin function to manage roles, pause state, and blacklist
     * @param action 1=grantRole, 2=revokeRole, 3=pause, 4=unpause, 5=blacklist, 6=unblacklist
     * @param target Address to affect (for role and blacklist actions)
     * @param data Role bytes32 for role actions, ignored for other actions
     */
    function adminControl(uint8 action, address target, bytes32 data) public onlyRole(DEFAULT_ADMIN_ROLE) {
        if (action == 1) {
            // Grant role
            _grantRole(data, target);
        } else if (action == 2) {
            // Revoke role
            _revokeRole(data, target);
        } else if (action == 3) {
            // Pause
            require(!_paused, "Already paused");
            _paused = true;
            emit Paused(msg.sender);
        } else if (action == 4) {
            // Unpause
            require(_paused, "Not paused");
            _paused = false;
            emit Unpaused(msg.sender);
        } else if (action == 5) {
            // Blacklist
            require(!isBlackListed[target], "Already blacklisted");
            isBlackListed[target] = true;
            emit BlacklistUpdated(target, true);
        } else if (action == 6) {
            // Unblacklist
            require(isBlackListed[target], "Not blacklisted");
            isBlackListed[target] = false;
            emit BlacklistUpdated(target, false);
        } else {
            revert("Invalid action");
        }
    }

    /**
     * @dev Combined token management function for controllers
     * @param action 1=issue, 2=redeem, 3=destroyBlackFunds, 4=setFeeParameters
     * @param target Address to affect
     * @param amount Amount for token operations or basis points for fee setting
     * @param maxFee Maximum fee (only used for action 4)
     */
    function controllerAction(uint8 action, address target, uint256 amount, uint256 maxFee) public onlyRole(CONTROLLER_ROLE) {
        if (action == 1) {
            // Issue tokens
            _mint(target, amount);
            emit TokensIssued(target, amount);
        } else if (action == 2) {
            // Redeem tokens
            if (target != msg.sender) {
                uint256 currentAllowance = _allowances[target][msg.sender];
                require(currentAllowance >= amount, "Exceeds allowance");
                unchecked {
                    _approve(target, msg.sender, currentAllowance - amount);
                }
            }
            _burn(target, amount);
            emit TokensRedeemed(target, amount);
        } else if (action == 3) {
            // Destroy blacklisted funds
            require(isBlackListed[target], "Not blacklisted");
            uint256 balance = _balances[target];
            _burn(target, balance);
            emit TokensRedeemed(target, balance);
        } else if (action == 4) {
            // Set fee parameters
            require(amount < 20, "Basis points too high");
            require(maxFee < 50 * (10 ** _decimals), "Maximum fee too high");
            basisPointsRate = amount;
            maximumFee = maxFee;
            emit FeeParametersChanged(amount, maxFee);
        } else {
            revert("Invalid action");
        }
    }

    /**
     * @dev Transfers tokens to a specified address
     * @param to The recipient address
     * @param amount The amount to transfer
     * @return A boolean indicating if the operation was successful
     */
    function transfer(address to, uint256 amount) public whenNotPaused returns (bool) {
        _transfer(msg.sender, to, amount);
        return true;
    }

    /**
     * @dev Approves a spender to spend tokens
     * @param spender The spender address
     * @param amount The amount to approve
     * @return A boolean indicating if the operation was successful
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /**
     * @dev Transfers tokens from one address to another using allowance
     * @param from The sender address
     * @param to The recipient address
     * @param amount The amount to transfer
     * @return A boolean indicating if the operation was successful
     */
    function transferFrom(address from, address to, uint256 amount) public whenNotPaused returns (bool) {
        _spendAllowance(from, msg.sender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Internal function to grant a role
     */
    function _grantRole(bytes32 role, address account) internal {
        if (!_roles[role][account]) {
            _roles[role][account] = true;
            emit RoleGranted(role, account, msg.sender);
        }
    }

    /**
     * @dev Internal function to revoke a role
     */
    function _revokeRole(bytes32 role, address account) internal {
        if (_roles[role][account]) {
            _roles[role][account] = false;
            emit RoleRevoked(role, account, msg.sender);
        }
    }

    /**
     * @dev Internal transfer function with fee handling
     */
    function _transfer(address from, address to, uint256 amount) internal {
        require(from != address(0), "Transfer from zero address");
        require(to != address(0), "Transfer to zero address");
        require(!isBlackListed[from], "Sender is blacklisted");
        require(!isBlackListed[to], "Recipient is blacklisted");

        uint256 fee = _calculateFee(amount);
        uint256 sendAmount = amount - fee;

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "Exceeds balance");

        unchecked {
            _balances[from] = fromBalance - amount;
        }

        _balances[to] += sendAmount;
        emit Transfer(from, to, sendAmount);

        if (fee > 0) {
            // Use first controller as fee recipient
            address feeReceiver = msg.sender;
            for (uint256 i = 0; i < 3; i++) { // Limit iterations for gas efficiency
                if (hasRole(CONTROLLER_ROLE, feeReceiver)) {
                    break;
                }
                feeReceiver = msg.sender; // Fallback to sender if no controller found
            }

            _balances[feeReceiver] += fee;
            emit Transfer(from, feeReceiver, fee);
        }
    }

    /**
     * @dev Calculates the fee for a given amount
     */
    function _calculateFee(uint256 amount) internal view returns (uint256) {
        uint256 fee = (amount * basisPointsRate) / 10000;
        if (fee > maximumFee) {
            fee = maximumFee;
        }
        return fee;
    }

    /**
     * @dev Internal approval function
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "Approve from zero address");
        require(spender != address(0), "Approve to zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Internal function to spend allowance
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal {
        uint256 currentAllowance = _allowances[owner][spender];
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "Insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Internal mint function
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "Mint to zero address");

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Internal burn function
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "Burn from zero address");

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "Burn exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }
}

Tags:
ERC20, Token|addr:0xe4e501933e0a284c27022ca9f283fd7d1cb100f4|verified:true|block:23599479|tx:0xc4e2ee3e228792e661b61a22ce98f8b2392ff6acecfc99d9551dfc6efd1803da|first_check:1760771200

Submitted on: 2025-10-18 09:06:42

Comments

Log in to comment.

No comments yet.