contract ERC20Lockable is ERC20 {
    using SafeMath for uint256;

    /**
     * @dev Emitted when funds have been sent to the contract and locked.
     */
    event FundsLocked(address indexed payee, uint256 amount, uint256 minUnlockTime);

    /**
     * @dev Emitted when previously locked funds have been unlocked and sent to the payee.
     */
    event FundsUnlocked(address indexed payee, uint256 amount);

    /**
     * @dev Struct for a locked balance (including its earliest possible unlock time).
     */
    struct LockedBalance {
        uint256 amount;
        uint256 minUnlockTime;
    }

    /**
     * @dev Maps locked balances (and their earliest possible unlock times) to addresses.
     */
    mapping(address => LockedBalance[]) private _lockedBalances;

    /**
     * @dev Counts the number of locked balances (separated by their earliest possible unlock times) of an address.
     */
    function getLockedBalanceCount(address payee) external view returns (uint256) {
        return _lockedBalances[payee].length;
    }

    /**
     * @dev Returns the locked balance of an address at the specified index.
     */
    function getLockedBalance(address payee, uint256 index) external view returns (uint256) {
        return _lockedBalances[payee][index].amount;
    }

    /**
     * @dev Returns the earliest possible unlock time of the locked balance of an address at the specified index.
     */
    function getLockedBalanceMinUnlockTime(address payee, uint256 index) external view returns (uint256) {
        return _lockedBalances[payee][index].minUnlockTime;
    }

    /**
     * @dev Stores the specified amount as credit to be unlocked at or after the specified time.
     * @param payee The destination address of the funds.
     * @param amount The amount to be locked.
     * @param minUnlockTime The earliest possible time at or after which the funds can be unlocked.
     */
    function _lockFunds(address payee, uint256 amount, uint256 minUnlockTime) internal returns (bool) {
        _mint(address(this), amount);
        _lockedBalances[payee].push(LockedBalance(amount, minUnlockTime));
        emit FundsLocked(payee, amount, minUnlockTime);
        return true;
    }

    /**
     * @dev Transfer previously locked funds to a payee at or after the minimum unlock time.
     * @param payee The address whose previously locked funds will be unlocked and transferred to.
     */
    function unlockFunds(address payee) external returns (bool) {
        uint256 payment = 0;

        for (uint256 i = 0; i < _lockedBalances[payee].length; i++) if (block.timestamp >= _lockedBalances[payee][i].minUnlockTime) {
            payment = payment.add(_lockedBalances[payee][i].amount);
            for (uint j = i; j < _lockedBalances[payee].length - 1; j++) _lockedBalances[payee][j] = _lockedBalances[payee][j + 1];
            _lockedBalances[payee].length--;
            i--;
        }
        
        require(payment > 0, "No funds available to unlock.");
        _transfer(address(this), payee, payment);
        emit FundsUnlocked(payee, payment);
        return true;
    }
}
/**
 * @title ERC20Lockable
 * @dev ERC20 token in which funds can be provably locked until a specified timestamp.
 */
function getLockedBalance(address payee, uint256 index) external view returns (uint256) {
    return _lockedBalances[payee][index].amount;
}

/**
 * @dev Returns the locked balance of an address at the specified index.
 */