PloopToken

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/PloopToken.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title PloopToken (capped ERC20) — v1.6
/// @notice Hard-capped at 1,000,000,000 PLOOP. Single minter (set by owner).
///         Engine expects: cap(), setMinter(address), mint(to,amount), burn(amount),
///         standard ERC20 (transfer/transferFrom/approve).
contract PloopToken {
    // ============ ERC20 Storage ============
    string public name;
    string public symbol;
    uint8  public constant decimals = 18;

    uint256 public totalSupply;
    mapping(address => uint256)                       public balanceOf;
    mapping(address => mapping(address => uint256))   public allowance;

    // ============ Cap / Roles ============
    uint256 public constant CAP_TOKENS = 1_000_000_000 ether; // 1B * 1e18

    address public owner;
    address public minter;

    // ============ Events ============
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    event OwnerSet(address indexed newOwner);
    event MinterSet(address indexed newMinter);

    // ============ Errors ============
    error NotOwner();
    error NotMinter();
    error CapExceeded();

    // ============ Modifiers ============
    modifier onlyOwner() {
        if (msg.sender != owner) revert NotOwner();
        _;
    }

    modifier onlyMinter() {
        if (msg.sender != minter) revert NotMinter();
        _;
    }

    // ============ Constructor ============
    /// @param _name   ERC20 name (e.g., "Ploop Token")
    /// @param _symbol ERC20 symbol (e.g., "PLOOP")
    /// @param _owner  Initial owner (can set/rotate minter)
    constructor(string memory _name, string memory _symbol, address _owner) {
        name  = _name;
        symbol= _symbol;
        owner = _owner;
        emit OwnerSet(_owner);
    }

    // ============ View Helpers ============
    function cap() external pure returns (uint256) {
        return CAP_TOKENS;
    }

    // ============ Owner Controls ============
    function setOwner(address newOwner) external onlyOwner {
        owner = newOwner;
        emit OwnerSet(newOwner);
    }

    /// @notice Set (or rotate) the single minter. Expected to be the Engine.
    function setMinter(address newMinter) external onlyOwner {
        minter = newMinter;
        emit MinterSet(newMinter);
    }

    // ============ Mint / Burn ============
    /// @notice Mint new tokens up to the hard cap.
    function mint(address to, uint256 amount) external onlyMinter {
        uint256 newTotal = totalSupply + amount;
        if (newTotal > CAP_TOKENS) revert CapExceeded();

        totalSupply = newTotal;
        unchecked {
            balanceOf[to] += amount;
        }
        emit Transfer(address(0), to, amount);
    }

    /// @notice Burn caller's tokens (Engine or users can burn their own balance).
    function burn(uint256 amount) external {
        uint256 bal = balanceOf[msg.sender];
        require(bal >= amount, "INSUFFICIENT_BALANCE");
        unchecked {
            balanceOf[msg.sender] = bal - amount;
            totalSupply -= amount;
        }
        emit Transfer(msg.sender, address(0), amount);
    }

    // ============ ERC20 ============
    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transfer(address to, uint256 amount) external returns (bool) {
        _transfer(msg.sender, to, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        if (allowed != type(uint256).max) {
            require(allowed >= amount, "ALLOWANCE");
            unchecked {
                allowance[from][msg.sender] = allowed - amount;
            }
            emit Approval(from, msg.sender, allowance[from][msg.sender]);
        }
        _transfer(from, to, amount);
        return true;
    }

    // ============ Internal ============
    function _transfer(address from, address to, uint256 amount) internal {
        require(to != address(0), "ZERO_TO");
        uint256 bal = balanceOf[from];
        require(bal >= amount, "BALANCE");
        unchecked {
            balanceOf[from] = bal - amount;
            balanceOf[to] += amount;
        }
        emit Transfer(from, to, amount);
    }
}
"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=lib/forge-std/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 400
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true
  }
}}

Tags:
Factory|addr:0xec8301f255ac509016d6a7b9b4822c0cd1cbff88|verified:true|block:23683609|tx:0x94a4f3c8dc240cd94808bd5ae1f06a259f7373cc1553d362a0c435c6dd7220ae|first_check:1761758495

Submitted on: 2025-10-29 18:21:36

Comments

Log in to comment.

No comments yet.