contract rSwap is Ownable {
    // solhint-disable not-rely-on-time

    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    event TokensSwapped(address account, uint256 amount);

    // Durations and timestamps in UNIX time, also in block.timestamp.
    uint256 public immutable start;
    uint256 public immutable duration;
    IERC20 public immutable rHEGIC;
    IERC20 public immutable HEGIC;

    uint public released;

    /**
     * @dev Creates a contract that can be used for swapping rHEGIC into HEGIC
     * @param _start UNIX time at which the unlock period starts
     * @param _duration Duration in seconds for unlocking tokens
     */
    constructor (uint256 _start, uint256 _duration, IERC20 _rHEGIC, IERC20 _HEGIC) {
        // solhint-disable-next-line max-line-length
        require(_duration > 0, "TokenSwap: duration is 0");
        // solhint-disable-next-line max-line-length
        require(_start.add(_duration) > block.timestamp, "rSwap: The final unlock time point is before the current time point");

        duration = _duration;
        start = _start;
        rHEGIC =_rHEGIC;
        HEGIC = _HEGIC;
    }

    function swap(uint amount) external {
        require(availableAmount() > amount, "rSwap: This amount has not been unlocked yet");

        rHEGIC.safeTransferFrom(msg.sender, address(this), amount);
        released = released.add(amount);
        HEGIC.safeTransfer(msg.sender, amount);

        emit TokensSwapped(msg.sender, amount);
    }

    function withdrawERC20(IERC20 token) external onlyOwner {
        token.safeTransfer(owner(), token.balanceOf(address(this)));
    }

    /**
     * @dev Calculates the amount of tokens that has already been unlocked but hasn't been swapped yet
     */
    function availableAmount() public view returns (uint256) {
        return totalUnlockedAmount().sub(released);
    }

    /**
     * @dev Calculates the total amount of tokens that has already been unlocked
     */
    function totalUnlockedAmount() public view returns (uint256) {
        uint256 currentBalance = HEGIC.balanceOf(address(this));
        uint256 totalBalance = currentBalance.add(released);
        if(block.timestamp < start)
            return 0;
        if (block.timestamp >= start.add(duration)) {
            return totalBalance;
        } else {
            return totalBalance.mul(block.timestamp.sub(start)).div(duration);
        }
    }
}
/**
 * @title rSwap
 * @dev A token swap contract that gradually releases tokens on its balance
 */
function totalUnlockedAmount() public view returns (uint256) {
    uint256 currentBalance = HEGIC.balanceOf(address(this));
    uint256 totalBalance = currentBalance.add(released);
    if(block.timestamp < start)
        return 0;
    if (block.timestamp >= start.add(duration)) {
        return totalBalance;
    } else {
        return totalBalance.mul(block.timestamp.sub(start)).div(duration);
    }
}

/**
 * @dev Calculates the total amount of tokens that has already been unlocked
 */