// File: Action.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./Ownable.sol";

contract Action is Ownable {
    mapping(address => bool) private _blacklist;
    bool private _pause;

    event AddBlacklist(address indexed account);
    event RemoveBlacklist(address indexed account);
    event Pause(address indexed account);
    event UnPause(address indexed account);

    constructor() {
        _pause = false;
    }



    function pause() public onlyOwner returns(bool) {
        require(!_pause, "Action: already pause");
        _pause = true;
        emit Pause(msg.sender);
        return true;
    }

    function unpause() public onlyOwner returns(bool) {
        require(_pause, "Action: already  unpause");
        _pause = false;
        emit UnPause(msg.sender);
        return true;
    }

    function paused() public view returns (bool) {
        return _pause;
    }

    function addBlacklist(
        address blackAddress
    ) public onlyOwner returns (bool) {
        require(!_blacklist[blackAddress], "Action: already blacklisted");
        _blacklist[blackAddress] = true;
        emit AddBlacklist(blackAddress);
        return true;
    }

    function removeBlacklist(
        address blackAddress
    ) public onlyOwner returns (bool) {
        require(_blacklist[blackAddress], 'Action: not blacklisted');
        _blacklist[blackAddress] = false;
        emit RemoveBlacklist(blackAddress);
        return true;
    }

    function blackListed(address account) public view returns (bool) {
        return _blacklist[account];
    }

    function _beforeTransferToken(
        address from,
        address to,
        uint256 amount
    ) internal view {
        require(!_blacklist[from], "Action: Sender blacklisted");
        require(!_blacklist[to], "Action: Recipient blacklisted");
        require(amount > 0, "Action: transfer amount has to big than 0");
        require(!_pause, "Action: paused");
    }
}

// File: CryptoCarbonEnergy.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./Action.sol";
import "./IERC20.sol";
import "./SafeMath.sol";

/*


   _____   _______   _____ _____ ___     ___   _   ___ ___  ___  _  _   ___ _  _ ___ ___  _____   __
  / __\ \ / / _ \ \ / / _ \_   _/ _ \   / __| /_\ | _ \ _ )/ _ \| \| | | __| \| | __| _ \/ __\ \ / /
 | (__ \ V /|   /\ V /|  _/ | || (_) | | (__ / _ \|   / _ \ (_) | .` | | _|| .` | _||   / (_ |\ V /
  \___| |_| |_|_\ |_| |_|   |_| \___/   \___/_/ \_\_|_\___/\___/|_|\_| |___|_|\_|___|_|_\\___| |_|


*/

// Contract to define a ERC20 Token with added functionality of mint and burn
contract CryptoCarbonEnergy is IERC20, SafeMath, Action {
    uint256 private _totalSupply; // Total supply of tokens
    string private _name; // Name of the token
    string private _symbol; // Symbol of the token

    // Mapping to keep track of token balances of each address
    mapping(address => uint) private _balances;

    // Mapping to keep track of allowed transfer of tokens for each address
    mapping(address => mapping(address => uint256)) private _allowances;

    // Constructor to set the name and symbol of the token
    constructor() {
        _name = "Crypto Carbon Energy";
        _symbol = "CYCE";
    }

    // Function to get the total supply of tokens
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    // Function to get the balance of tokens for a specific address
    function balanceOf(
        address account
    ) public view virtual override returns (uint256) {
        return _balances[account];
    }

    // Function to get the allowed transfer of tokens for a specific address
    function allowance(
        address tokenOwner,
        address spender
    ) public view virtual override returns (uint256) {
        return _allowances[tokenOwner][spender];
    }

    // Function to get the name of the token
    function name() public view returns (string memory) {
        return _name;
    }

    // Function to get the symbol of the token
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    // Function to get the decimal places of the token
    function decimals() public pure returns (uint8) {
        return 6;
    }

    // Function to approve a specific address to transfer a specified amount of tokens
    function approve(
        address spender,
        uint256 amount
    ) public virtual override returns (bool) {
        // Require that the spender address is not zero address
        require(spender != address(0), "ERC20: approve to the zero address");
        // Require that the amount is greater than zero
        require(amount > 0, "invalid value");
        // Update the allowed transfer of tokens
        _allowances[msg.sender][spender] = amount;
        // Emit an approval event
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    // Function to transfer a specified amount of tokens from the sender to a recipient
    function transfer(
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        // Call the private transfer function
        _transfer(msg.sender, to, amount);
        return true;
    }

    // Function to transfer a specified amount of tokens from one address to another

    // Transfer tokens from one address to another
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        // Ensure that the amount of tokens being transferred does not exceed the approved amount for the transferor
        require(
            amount <= _allowances[from][msg.sender],
            "ERC20: approve to the zero address"
        );
        // Call the private function to handle the transfer
        _transfer(from, to, amount);
        // Decrement the approved amount
        _allowances[from][msg.sender] -= amount;
        return true;
    }

    // Private function to handle the transfer of tokens
    function _transfer(address from, address to, uint256 amount) private {
        // Ensure that the transferor address is not the zero address
        require(from != address(0), "ERC20: transfer from the zero address");
        // Ensure that the recipient address is not the zero address
        require(to != address(0), "ERC20: transfer to the zero address");
        // Ensure that the transferor has enough tokens to transfer
        require(
            _balances[from] >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        // Function call for any additional logic to be executed before the transfer
        _beforeTransferToken(from, to, amount);
        // Decrement the transferor's balance
        _balances[from] = safeSub(_balances[from], amount);
        // Increment the recipient's balance
        _balances[to] = safeAdd(_balances[to], amount);
        emit Transfer(from, to, amount);
    }

    // Function to mint new tokens and increase the total supply
    /**
     * @dev mint : To increase total supply of tokens
     */
    function mint(address to, uint256 tokens) public onlyOwner returns (bool) {
        // Increase the total supply
        _totalSupply = safeAdd(_totalSupply, tokens);
        // Increase the balance of the contract owner
        _balances[to] = safeAdd(_balances[to], tokens);
        emit Transfer(address(0), to, tokens);
        return true;
    }

    // Function to burn tokens and decrease the total supply
    /**
     * @dev burn : To decrease total supply of tokens
     */
    function burn(uint tokens) public onlyOwner returns (bool) {
        // Ensure that the contract owner has enough tokens to burn
        require(
            _balances[msg.sender] >= tokens,
            "ERC20: burn amount exceeds balance"
        );
        // Decrease the total supply
        _totalSupply = safeSub(_totalSupply, tokens);
        // Decrease the balance of the contract owner
        _balances[msg.sender] = safeSub(_balances[msg.sender], tokens);
        emit Transfer(msg.sender, address(0), tokens);
        return true;
    }
}

// File: IERC20.sol



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

// Abstract contract defining interface for an ERC20 token
abstract contract IERC20 {
    // Get the total supply of tokens
    function totalSupply() external view virtual returns (uint256);

    // Transfer specified number of tokens from caller to the `to` address
    function transfer(
        address to,
        uint256 tokens
    ) external virtual returns (bool);

    // Approve the `spender` address to spend the specified number of tokens on behalf of the caller
    function approve(
        address spender,
        uint256 tokens
    ) external virtual returns (bool);

    // Get the approved number of tokens for a `spender` address from the `tokenOwner` address
    function allowance(
        address tokenOwner,
        address spender
    ) external view virtual returns (uint256);

    // Transfer specified number of tokens from `from` address to the `to` address
    function transferFrom(
        address from,
        address to,
        uint256 tokens
    ) external virtual returns (bool);

    // Get the balance of tokens for an `account` address
    function balanceOf(address account) public view virtual returns (uint256);

    // Event emitted when tokens are transferred
    event Transfer(address indexed from, address indexed to, uint256 tokens);

    // Event emitted when an approval is made
    event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens);
}

// File: Ownable.sol



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

contract Ownable {
    address private _owner;

    constructor() {
        _owner = msg.sender;
    }

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );
    modifier onlyOwner() {
        require(msg.sender == _owner, "Unauthorized");
        _;
    }

    function isContract(address _addr) private view returns (bool) {
        uint32 size;
        assembly {
            size := extcodesize(_addr)
        }
        return (size > 0);
    }

    function transferOwnership(
        address newOwner
    ) public onlyOwner returns (bool) {
        require(
            isContract(newOwner),
            "Ownable: New owner address is not a contract"
        );
        require(_owner != newOwner, "Ownable: The same owner");
        _transferOwnership(newOwner);
        return true;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _transferOwnership(address newOwner) private {
        _owner = newOwner;
        emit OwnershipTransferred(msg.sender, newOwner);
    }

    function renounceOwnership() public onlyOwner returns (bool) {
        _transferOwnership(address(0));
        return true;
    }
}

// File: SafeMath.sol



// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;

contract SafeMath {
    function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;
        return c;
    }
}