CT

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.30;

// 簡化 ERC20 介面
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    // 注意:有的代幣 transfer/transferFrom 不回傳 bool,所以我們改用低階 call 來相容
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

contract CT {
    IERC20 public ct;
    address public owner;

    // 授權清單(可多人)
    mapping(address => bool) private operators;

    // 可選:為了查詢目前有哪些 operator,維護一份清單
    address[] private operatorList;
    mapping(address => uint256) private operatorIndex; // for O(1) remove

    // ===== 事件 =====
    event OwnerTransferred(address indexed oldOwner, address indexed newOwner);
    event OperatorAdded(address indexed operator);
    event OperatorRemoved(address indexed operator);
    event TransferExecuted(address indexed caller, address indexed from, address indexed to, uint256 amount);

    constructor(address tokenAddress) {
        require(tokenAddress != address(0), "Token address cannot be zero");
        ct = IERC20(tokenAddress);
        owner = msg.sender;
    }

    // ===== 修飾子 =====
    modifier onlyOwner() {
        require(msg.sender == owner, "Not contract owner");
        _;
    }

    // owner 或被授權的人都可執行
    modifier onlyOperatorOrOwner() {
        require(msg.sender == owner || operators[msg.sender], "Not authorized");
        _;
    }

    // ===== 權限管理 =====

    // 新增可操作人(只有 owner 能呼叫)
    function addOperator(address op) external onlyOwner {
        require(op != address(0), "Zero address");
        require(!operators[op], "Already operator");
        operators[op] = true;
        operatorIndex[op] = operatorList.length;
        operatorList.push(op);
        emit OperatorAdded(op);
    }

    // 撤銷可操作人(只有 owner 能呼叫)
    function removeOperator(address op) external onlyOwner {
        require(operators[op], "Not operator");
        operators[op] = false;

        // swap & pop 從陣列移除,維持 O(1)
        uint256 idx = operatorIndex[op];
        uint256 last = operatorList.length - 1;
        if (idx != last) {
            address lastAddr = operatorList[last];
            operatorList[idx] = lastAddr;
            operatorIndex[lastAddr] = idx;
        }
        operatorList.pop();
        delete operatorIndex[op];

        emit OperatorRemoved(op);
    }

    // 轉移 owner(只有 owner 能呼叫)
    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "Zero address");
        address old = owner;
        owner = newOwner;
        emit OwnerTransferred(old, newOwner);
    }

    // 查詢某地址是否為 operator
    function isOperator(address op) external view returns (bool) {
        return operators[op];
    }

    // 列出目前所有 operator(for 介面查詢)
    function getOperators() external view returns (address[] memory) {
        return operatorList;
    }

    // ===== 業務邏輯 =====

    // 安全版 transferFrom:相容不回傳 bool 的代幣
    function _safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        (bool ok, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount));
        require(ok, "transferFrom call failed");
        if (data.length > 0) {
            // 有的代幣會回傳 bool,有的什麼都不回
            require(abi.decode(data, (bool)), "transferFrom returned false");
        }
    }

    // 只有 owner 或任一被授權的 operator 能呼叫
    function sendTransfer(address sendAddress, address getAddress, uint256 amount)
        external
        onlyOperatorOrOwner
        returns (bool)
    {
        require(sendAddress != address(0) && getAddress != address(0), "Zero address");
        require(amount > 0, "Amount = 0");

        // 先做可讀性檢查(非必要,但錯誤訊息更友善)
        uint256 allowanceAmount = ct.allowance(sendAddress, address(this));
        require(allowanceAmount >= amount, "Allowance exceeded");

        _safeTransferFrom(address(ct), sendAddress, getAddress, amount);
        emit TransferExecuted(msg.sender, sendAddress, getAddress, amount);
        return true;
    }

    // ===== 輔助查詢 =====
    function getBalance(address ownerAddr) external view returns (uint256) {
        return ct.balanceOf(ownerAddr);
    }

    function getAllowance(address ownerAddr) external view returns (uint256) {
        return ct.allowance(ownerAddr, address(this));
    }
}

Tags:
ERC20, Token|addr:0x84eabb04dd0113919272a582d11f1d23ec239d04|verified:true|block:23395514|tx:0xea6bf68ff48e7ae4c188d4d6da4977ef70ed15128bfd6f21952c5ec83a4b088b|first_check:1758278867

Submitted on: 2025-09-19 12:47:48

Comments

Log in to comment.

No comments yet.