contract MUEWorld is ERC20, ERC20Burnable, Ownable {
	uint8 public DECIMALS = 18;
	uint256 public TOTAL_SUPPLY = 3000000000 * 1000000000000000000; // 총 발행량 30억 3000000000.0000
    uint256 public INITIAL_SUPPLY = 1000000000 * 1000000000000000000; // 초기 발행량 10억 1000000000.0000

    uint256 private _cap;

	// Lock
	mapping (address => TokenTimelock) public lockStatus;
    
	event Lock(address _receiver, uint256 _amount);
	event Unlock(address _receiver, uint256 _amount);
	event Mint(uint256 _supplied, uint256 _amount, uint256 _totalSupply);
	event Burn(address _account, uint256 _amount, uint256 _totalSupply);

    /**
     * @dev Sets the value of the `cap`. This value is immutable, it can only be
     * set once during construction.
     */
  	constructor() ERC20("Mue", "MUE") public {
		_setupDecimals(DECIMALS);
		// should set cap before mint
        _cap = TOTAL_SUPPLY;
        _mint(msg.sender, INITIAL_SUPPLY);
	}

    /**
     * @dev Returns the cap on the token's total supply.
     */
    function cap() public view returns (uint256) {
        return _cap;
    }

    /**
     * @dev See {ERC20-_beforeTokenTransfer}.
     *
     * Requirements:
     *
     * - minted tokens must not cause the total supply to go over the cap.
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);

        if (from == address(0)) { // When minting tokens
            require(totalSupply().add(amount) <= _cap, "ERC20Capped: cap exceeded");
        }
    }

	function mintToken(uint256 amount) onlyOwner public {
		uint256 supplied = totalSupply();
        _mint(owner(), amount);
		emit Mint(supplied, amount, totalSupply());
	}

	function burnToken(address account, uint256 amount) onlyOwner public {
        _burn(account, amount);
		emit Burn(account, amount, totalSupply());
	}

	function lockToken(address beneficiary, uint256 amount) onlyOwner public {
        require(beneficiary != address(0), "lockToken: lock to the zero address");

		uint256 releaseTime = block.timestamp + 1 seconds;
		TokenTimelock lockContract = new TokenTimelock(this, beneficiary, releaseTime);

		transfer(address(lockContract), amount);
		lockStatus[beneficiary] = lockContract;
		emit Lock(beneficiary, amount);
	}

	function unlockToken(address beneficiary) onlyOwner public {
        require(beneficiary != address(0), "unlockToken: unlock to the zero address");

		TokenTimelock lockContract = lockStatus[beneficiary];

		IERC20 token = lockContract.token();
		uint256 amount = token.balanceOf(beneficiary);
		lockContract.release();
		emit Unlock(beneficiary, amount);
	}

}
// import "@openzeppelin/contracts/token/ERC20/TokenTimelock.sol";
function cap() public view returns (uint256) {
    return _cap;
}

/**
 * @dev Returns the cap on the token's total supply.
 */