CommunityToken

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

/* ===================== Shared Base: Ownership ===================== */
abstract contract OwnableBase {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    address public owner;
    constructor(address initialOwner) {
        require(initialOwner != address(0), "owner=0");
        owner = initialOwner;
        emit OwnershipTransferred(address(0), initialOwner);
    }
    modifier onlyOwner() { require(msg.sender == owner, "only owner"); _; }
    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "newOwner=0");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }
}

/* ===================== Optional: Global Fee Registry ===================== */
contract FeeRegistry is OwnableBase {
    address public feeSink;  // where protocol skim goes
    uint16  public feeBps;   // basis points (e.g., 20 = 0.20%)
    event FeeUpdated(address indexed sink, uint16 bps);
    constructor(address _owner, address _sink, uint16 _bps) OwnableBase(_owner) {
        require(_sink != address(0), "sink=0");
        require(_bps <= 1000, "bps>10%");
        feeSink = _sink;
        feeBps  = _bps;
        emit FeeUpdated(_sink, _bps);
    }
    function setFee(address sink, uint16 bps) external onlyOwner {
        require(sink != address(0), "sink=0");
        require(bps <= 1000, "bps>10%");
        feeSink = sink;
        feeBps  = bps;
        emit FeeUpdated(sink, bps);
    }
}

interface IFeeRegistry {
    function feeSink() external view returns (address);
    function feeBps()  external view returns (uint16);
}

/* ===================== Main tie-in interface ===================== */
interface IMain {
    function protocolFeeBps()  external view returns (uint16);
    function protocolFeeSink() external view returns (address);
}

/* ===================== Pause Base ===================== */
abstract contract PausableBase is OwnableBase {
    event Paused(address indexed account);
    event Unpaused(address indexed account);
    bool public paused;
    constructor(address o) OwnableBase(o) {}
    modifier whenNotPaused() { require(!paused, "paused"); _; }
    function pause()   external onlyOwner { paused = true;  emit Paused(msg.sender); }
    function unpause() external onlyOwner { paused = false; emit Unpaused(msg.sender); }
}

/* ===================== Satellite ERC20 with dual fee source ===================== */
contract CommunityToken is PausableBase {
    /* ERC20 metadata */
    string public name;
    string public symbol;
    function decimals() public pure returns (uint8) { return 18; }

    /* ERC20 storage */
    uint256 public totalSupply;
    mapping(address => uint256) private _bal;
    mapping(address => mapping(address => uint256)) private _allow;

    /* ERC20 events */
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed tokenOwner, address indexed spender, uint256 value);

    /* Fee source mode */
    enum FeeSource { Registry, Main }
    FeeSource public feeSource;

    /* Sources */
    address public registry;  // FeeRegistry (if using Registry mode)
    address public main;      // Main Cosigo (if using Main mode)

    /* Optional community fee (local) */
    address public communityTreasury;     // can be zero to disable
    uint16  public communityFeeBps;       // 0..1000 (0..10%)

    /* Optional: allow MAIN to pause when enabled */
    bool public mainGuardianEnabled;
    event FeeSourceChanged(FeeSource mode);
    event RegistryUpdated(address indexed registry);
    event MainUpdated(address indexed main);
    event MainGuardianToggled(bool enabled);
    event CommunityTreasuryUpdated(address indexed treasury);
    event CommunityFeeBpsUpdated(uint16 bps);

    modifier onlyOwnerOrMainGuardian() {
        require(msg.sender == owner || (mainGuardianEnabled && msg.sender == main), "owner/guardian only");
        _;
    }

    constructor(
        string memory name_,
        string memory symbol_,
        address owner_,                 // your EOA (MetaMask)
        uint8   feeSourceMode_,         // 0=Registry, 1=Main
        address registry_,              // required if Registry mode
        address main_,                  // required if Main mode
        address initialHolder_,         // initial recipient
        uint256 initialSupply_,         // 18 decimals
        address communityTreasury_,     // optional (0 to disable)
        uint16  communityFeeBps_        // usually 0
    ) PausableBase(owner_) {
        require(bytes(name_).length > 0 && bytes(symbol_).length > 0, "bad meta");
        require(initialHolder_ != address(0), "holder=0");
        require(communityFeeBps_ <= 1000, "comm>10%");

        name = name_;
        symbol = symbol_;

        // set fee source
        require(feeSourceMode_ <= 1, "mode");
        feeSource = FeeSource(feeSourceMode_);
        if (feeSource == FeeSource.Registry) {
            require(registry_ != address(0), "registry=0");
            registry = registry_;
            emit RegistryUpdated(registry_);
        } else {
            require(main_ != address(0), "main=0");
            main = main_;
            emit MainUpdated(main_);
        }

        communityTreasury = communityTreasury_;
        communityFeeBps   = communityFeeBps_;
        if (communityTreasury_ != address(0)) emit CommunityTreasuryUpdated(communityTreasury_);
        if (communityFeeBps_ > 0) emit CommunityFeeBpsUpdated(communityFeeBps_);

        _mint(initialHolder_, initialSupply_);
    }

    /* ----- owner controls ----- */
    function setRegistry(address r) external onlyOwner {
        require(r != address(0), "registry=0");
        registry = r;
        emit RegistryUpdated(r);
    }
    function setMain(address m) external onlyOwner {
        require(m != address(0), "main=0");
        main = m;
        emit MainUpdated(m);
    }
    function setFeeSource(uint8 mode) external onlyOwner {
        require(mode <= 1, "mode");
        feeSource = FeeSource(mode);
        emit FeeSourceChanged(feeSource);
    }
    function toggleMainGuardian(bool enabled) external onlyOwner {
        mainGuardianEnabled = enabled;
        emit MainGuardianToggled(enabled);
    }
    function setCommunityTreasury(address a) external onlyOwner {
        communityTreasury = a; // can be zero
        emit CommunityTreasuryUpdated(a);
    }
    function setCommunityFeeBps(uint16 bps) external onlyOwner {
        require(bps <= 1000, "max 10%");
        communityFeeBps = bps;
        emit CommunityFeeBpsUpdated(bps);
    }
    function mainPause() external onlyOwnerOrMainGuardian { paused = true;  emit Paused(msg.sender); }
    function mainUnpause() external onlyOwnerOrMainGuardian { paused = false; emit Unpaused(msg.sender); }

    /* ----- ERC20 views ----- */
    function balanceOf(address a) public view returns (uint256) { return _bal[a]; }
    function allowance(address o, address s) public view returns (uint256) { return _allow[o][s]; }

    /* ----- ERC20 writes ----- */
    function approve(address spender, uint256 value) external returns (bool) {
        _allow[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }
    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }
    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        uint256 cur = _allow[from][msg.sender];
        require(cur >= value, "allowance");
        unchecked { _allow[from][msg.sender] = cur - value; }
        emit Approval(from, msg.sender, _allow[from][msg.sender]);
        _transfer(from, to, value);
        return true;
    }

    /* ----- internal mint/burn (mint used in constructor) ----- */
    function _mint(address to, uint256 amt) internal {
        totalSupply += amt;
        _bal[to] += amt;
        emit Transfer(address(0), to, amt);
    }
    function _burn(address from, uint256 amt) internal {
        require(_bal[from] >= amt, "bal");
        unchecked { _bal[from] -= amt; }
        totalSupply -= amt;
        emit Transfer(from, address(0), amt);
    }

    /* ----- core transfer (ceil rounding, dual fee source) ----- */
    function _transfer(address from, address to, uint256 amount) internal whenNotPaused {
        require(from != address(0) && to != address(0), "zero addr");
        require(_bal[from] >= amount, "bal");
        if (amount == 0) { emit Transfer(from, to, 0); return; }

        // get protocol fee from selected source
        address sink;
        uint16  bps;
        if (feeSource == FeeSource.Registry) {
            sink = IFeeRegistry(registry).feeSink();
            bps  = IFeeRegistry(registry).feeBps();
        } else {
            sink = IMain(main).protocolFeeSink();
            bps  = IMain(main).protocolFeeBps();
        }
        require(sink != address(0), "sink=0");
        require(bps <= 1000, "bps>10%");

        uint256 protoFee = bps == 0 ? 0 : (amount * bps + 9999) / 10000;

        uint256 commFee = 0;
        if (communityTreasury != address(0) && communityFeeBps > 0) {
            commFee = (amount * communityFeeBps + 9999) / 10000;
        }
        require(protoFee + commFee <= amount, "fees>amount");

        uint256 net = amount - protoFee - commFee;

        unchecked { _bal[from] -= amount; }
        if (protoFee > 0) { _bal[sink] += protoFee; emit Transfer(from, sink, protoFee); }
        if (commFee  > 0) { _bal[communityTreasury] += commFee; emit Transfer(from, communityTreasury, commFee); }
        _bal[to] += net; emit Transfer(from, to, net);
    }
}

Tags:
ERC20, Multisig, Burnable, Pausable, Multi-Signature|addr:0x694c6e4cc4ce3fdf28d715347bd97a36bd411301|verified:true|block:23413340|tx:0x35ff52bd76f17c633fb8b3f75ece60bcf12f0b9a8d48f3dad4c33de3757270e3|first_check:1758531365

Submitted on: 2025-09-22 10:56:05

Comments

Log in to comment.

No comments yet.