contract TokenVesting {
    // The vesting schedule is time-based (i.e. using block timestamps as opposed to e.g. block numbers), and is
    // therefore sensitive to timestamp manipulation (which is something miners can do, to a certain degree). Therefore,
    // it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a
    // cliff period of a year and a duration of four years, are safe to use.
    // solhint-disable not-rely-on-time

    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    event TokensReleased(uint256 mTokensAmount, uint256 sTokensAmount);

    // beneficiary of tokens after they are released
    address private _beneficiary;

    // Durations and timestamps are expressed in UNIX time, the same units as block.timestamp.
    uint256 private _cliff;
    uint256 private _start;
    uint256 private _duration;

    address public mainToken;
    
    address public secondaryToken;
    
    uint256 public multiplier;
    
    address public factory;
    
    uint256 public totalVestingAmount;
    
    mapping (address => uint256) private _released;
    
    
    constructor (address beneficiary, uint256 amount, uint256 start, uint256 cliffDuration, uint256 duration, address _mainToken, address _secondaryToken, uint256 _multipier) public {
        require(beneficiary != address(0));
        require(cliffDuration <= duration);
        require(duration > 0);
        require(start.add(duration) > block.timestamp);

        _beneficiary = beneficiary;
        _duration = duration;
        _cliff = start.add(cliffDuration);
        _start = start;
        mainToken = _mainToken;
        secondaryToken = _secondaryToken;
        multiplier = _multipier;
        factory = msg.sender;
        totalVestingAmount = amount;
    }

    /**
     * @return the beneficiary of the tokens.
     */
    function beneficiary() public view returns (address) {
        return _beneficiary;
    }

    /**
     * @return the cliff time of the token vesting.
     */
    function cliff() public view returns (uint256) {
        return _cliff;
    }

    /**
     * @return the start time of the token vesting.
     */
    function start() public view returns (uint256) {
        return _start;
    }

    /**
     * @return the duration of the token vesting.
     */
    function duration() public view returns (uint256) {
        return _duration;
    }
    
    /**
     * @return the amount of the token released.
     */
    function available() public view returns (uint256) {
        return totalVestingAmount.sub(_released[mainToken]);
    }
    
    /**
     * @return the amount of the token released.
     */
    function released(address token) public view returns (uint256) {
        return (_released[token]);
    }
    
    /**
     * @return the amount of secondary tokens that has been accrued but hasn't been released yet.
     */
    function _accruedAmount() public view returns (uint256) {
        return _releasableAmount().mul(multiplier).div(10000);
    }
  
 
    /**
     * @notice Transfers vested tokens to beneficiary.
     */
    function release() public {
        uint256 unreleased = _releasableAmount();
        

        require(unreleased > 0);
        
        uint256 sTokensToRelease = unreleased.mul(multiplier).div(10000);

        _released[mainToken] = _released[mainToken].add(unreleased);
        _released[secondaryToken] = _released[secondaryToken].add(sTokensToRelease);


        IERC20(mainToken).safeTransfer(_beneficiary, unreleased);
        IERC20(secondaryToken).safeTransferFrom(factory, _beneficiary, sTokensToRelease);

        emit TokensReleased(unreleased, sTokensToRelease);
    }

    /**
     * @dev Calculates the amount that has already vested but hasn't been released yet.
     */
    function _releasableAmount() private view returns (uint256) {
        return _vestedAmount().sub(_released[mainToken]);
    }
    

    /**
     * @dev Calculates the amount that has already vested.
     */
    function _vestedAmount() private view returns (uint256) {
       

        if (block.timestamp < _cliff) {
            return 0;
        } else if (block.timestamp >= _start.add(_duration)) {
            return totalVestingAmount;
        } else {
            return totalVestingAmount.mul(block.timestamp.sub(_start)).div(_duration);
        }
    }
}
/**
 * @title TokenVesting
 * @dev A token holder contract that can release its token balance gradually like a
 * typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
 * owner.
 */
function beneficiary() public view returns (address) {
    return _beneficiary;
}

/**
 * @return the beneficiary of the tokens.
 */