abstract contract ERC20LockableStandard is
    ERC20Burnable,
    Ownable,
    Pausable,
    IERC865
{
    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override whenNotPaused {
        super._beforeTokenTransfer(from, to, amount);
    }

    uint256 _totalLockuped;
    mapping(address => uint256) private _lockupBalances;

    function totalLockuped() public view returns (uint256) {
        return _totalLockuped;
    }

    function lockupedBalanceOf(address account) public view returns (uint256) {
        return _lockupBalances[account];
    }

    function payableBalanceOf(address account) public view returns (uint256) {
        return super.balanceOf(account) - lockupedBalanceOf(account);
    }

    event IncreaseLockup(address indexed to, uint256 value);
    event DecreaseLockup(address indexed to, uint256 value);

    function increaseLockup(address account, uint256 addedValue)
        public
        onlyOwner
        returns (uint256)
    {
        require(
            payableBalanceOf(account) >= addedValue,
            "LIBEAR: increase amount exceeds balance"
        );

        _lockupBalances[account] += addedValue;
        _totalLockuped += addedValue;

        emit IncreaseLockup(account, addedValue);

        return _lockupBalances[account];
    }

    function decreaseLockup(address account, uint256 subtractedValue)
        public
        onlyOwner
        returns (uint256)
    {
        require(
            lockupedBalanceOf(account) >= subtractedValue,
            "LIBEAR: decrease amount exceeds lockup balance"
        );

        _lockupBalances[account] -= subtractedValue;
        _totalLockuped -= subtractedValue;

        emit DecreaseLockup(account, subtractedValue);
        return _lockupBalances[account];
    }

    function deliverPreSales(
        address[] calldata accounts,
        uint256[] calldata amounts
    ) public onlyOwner returns (bool) {
        require(accounts.length == amounts.length);

        uint256 totalAmount = 0;
        for (uint256 i = 0; i < amounts.length; i++) totalAmount += amounts[i];
        require(totalAmount <= super.balanceOf(_msgSender()));

        for (uint256 i = 0; i < accounts.length; i++) {
            transfer(accounts[i], amounts[i]);
            increaseLockup(accounts[i], amounts[i]);
        }

        return true;
    }

    function lockupExpirations(
        address[] calldata accounts,
        uint256[] calldata amounts
    ) public onlyOwner returns (bool) {
        require(
            accounts.length == amounts.length,
            "LIBEAR: The lengths of accounts and amounts are different."
        );
        for (uint256 i = 0; i < amounts.length; i++)
            require(
                lockupedBalanceOf(accounts[i]) >= amounts[i],
                "LIBEAR: decrease amount exceeds lockup balance"
            );

        for (uint256 i = 0; i < accounts.length; i++)
            decreaseLockup(accounts[i], amounts[i]);

        return true;
    }

    function transfer(address recipient, uint256 amount)
        public
        override
        returns (bool)
    {
        require(
            payableBalanceOf(_msgSender()) >= amount,
            "LIBEAR: transfer amount exceeds balance"
        );

        super.transfer(recipient, amount);
        return true;
    }

    /* Nonces of transfers performed */
    mapping(bytes => bool) signatures;
    /* mapping of nonces of each user */
    mapping(address => uint256) nonces;

    /**
     * @dev Submit a presigned transfer
     * @notice fee will be given to sender if it's a smart contract make sure it can accept funds
     * @param signature bytes The signature, issued by the owner.
     * @param to address The address which you want to transfer to.
     * @param amount uint256 The amount of tokens to be transferred.
     * @param fee uint256 The amount of tokens paid to msg.sender, by the owner.
     * @param nonce uint256 Presigned transaction number.
     */
    function transferPreSigned(
        bytes memory signature,
        address to,
        uint256 amount,
        uint256 fee,
        uint256 nonce
    ) public override returns (bool) {
        require(to != address(0), "LIBEAR: Invalid _to address");
        require(
            signatures[signature] == false,
            "LIBEAR: signature hash was already used"
        );

        bytes32 preSignedHashedMessage = getEthSignedMessage(
            address(this),
            to,
            amount,
            fee,
            nonce
        );
        address from = ECDSA.recover(preSignedHashedMessage, signature);

        require(from != address(0), "LIBEAR: Invalid from address recovered");
        require(
            payableBalanceOf(from) >= amount + fee,
            "LIBEAR: amount exceeds payable balance."
        );
        require(
            nonce > nonces[_msgSender()],
            "LIBEAR: It's an old version of the transaction."
        );

        signatures[signature] = true;
        nonces[_msgSender()] = nonce;

        _transfer(from, to, amount);
        _transfer(from, msg.sender, fee);

        emit TransferPreSigned(from, to, msg.sender, amount, fee);
        return true;
    }

    /**
     * @dev Hash (keccak256) of the payload used by transferPreSigned
     * @notice fee will be given to sender if it's a smart contract make sure it can accept funds
     * @param token address The address of the token.
     * @param to address The address which you want to transfer to.
     * @param amount uint256 The amount of tokens to be transferred.
     * @param fee uint256 The amount of tokens paid to msg.sender, by the owner.
     * @param nonce uint256 Presigned transaction number.
     */
    function getTransferPreSignedHash(
        address token,
        address to,
        uint256 amount,
        uint256 fee,
        uint256 nonce
    ) public pure returns (bytes32) {
        /* "0d98dcb1": getTransferPreSignedHash(address,address,uint256,uint256,uint256) */
        return
            keccak256(
                abi.encodePacked(
                    bytes4(0x0d98dcb1),
                    token,
                    to,
                    amount,
                    fee,
                    nonce
                )
            );
    }

    function getEthSignedMessage(
        address token,
        address to,
        uint256 amount,
        uint256 fee,
        uint256 nonce
    ) private pure returns (bytes32) {
        bytes32 hashedMessage = getTransferPreSignedHash(
            token,
            to,
            amount,
            fee,
            nonce
        );
        return
            keccak256(
                abi.encodePacked(
                    "\x19Ethereum Signed Message:\n32",
                    hashedMessage
                )
            );
    }
}
function transferPreSigned(
    bytes memory signature,
    address to,
    uint256 amount,
    uint256 fee,
    uint256 nonce
) public override returns (bool) {
    require(to != address(0), "LIBEAR: Invalid _to address");
    require(
        signatures[signature] == false,
        "LIBEAR: signature hash was already used"
    );

    bytes32 preSignedHashedMessage = getEthSignedMessage(
        address(this),
        to,
        amount,
        fee,
        nonce
    );
    address from = ECDSA.recover(preSignedHashedMessage, signature);

    require(from != address(0), "LIBEAR: Invalid from address recovered");
    require(
        payableBalanceOf(from) >= amount + fee,
        "LIBEAR: amount exceeds payable balance."
    );
    require(
        nonce > nonces[_msgSender()],
        "LIBEAR: It's an old version of the transaction."
    );

    signatures[signature] = true;
    nonces[_msgSender()] = nonce;

    _transfer(from, to, amount);
    _transfer(from, msg.sender, fee);

    emit TransferPreSigned(from, to, msg.sender, amount, fee);
    return true;
}

/**
 * @dev Submit a presigned transfer
 * @notice fee will be given to sender if it's a smart contract make sure it can accept funds
 * @param signature bytes The signature, issued by the owner.
 * @param to address The address which you want to transfer to.
 * @param amount uint256 The amount of tokens to be transferred.
 * @param fee uint256 The amount of tokens paid to msg.sender, by the owner.
 * @param nonce uint256 Presigned transaction number.
 */