{
    "Function": "slitherConstructorVariables",
    "File": "contracts/VTVLVesting.sol",
    "Parent Contracts": [
        "contracts/AccessProtected.sol",
        "node_modules/@openzeppelin/contracts/utils/Context.sol"
    ],
    "High-Level Calls": [],
    "Internal Calls": [],
    "Library Calls": [],
    "Low-Level Calls": [],
    "Code": "contract VTVLVesting is Context, AccessProtected {\n    using SafeERC20 for IERC20;\n\n    /**\n    @notice Address of the token that we're vesting\n     */\n    IERC20 public immutable tokenAddress;\n\n    /**\n    @notice How many tokens are already allocated to vesting schedules.\n    @dev Our balance of the token must always be greater than this amount.\n    * Otherwise we risk some users not getting their shares.\n    * This gets reduced as the users are paid out or when their schedules are revoked (as it is not reserved any more).\n    * In other words, this represents the amount the contract is scheduled to pay out at some point if the \n    * owner were to never interact with the contract.\n    */\n    uint112 public numTokensReservedForVesting = 0;\n\n    /**\n    @notice A structure representing a single claim - supporting linear and cliff vesting.\n     */\n    struct Claim {\n        // Using 40 bits for timestamp (seconds)\n        // Gives us a range from 1 Jan 1970 (Unix epoch) up to approximately 35 thousand years from then (2^40 / (365 * 24 * 60 * 60) ~= 35k)\n        uint40 startTimestamp; // When does the vesting start (40 bits is enough for TS)\n        uint40 endTimestamp; // When does the vesting end - the vesting goes linearly between the start and end timestamps\n        uint40 cliffReleaseTimestamp; // At which timestamp is the cliffAmount released. This must be <= startTimestamp\n        uint40 releaseIntervalSecs; // Every how many seconds does the vested amount increase. \n        \n        // uint112 range: range 0 \u2013     5,192,296,858,534,827,628,530,496,329,220,095.\n        // uint112 range: range 0 \u2013                             5,192,296,858,534,827.\n        uint112 linearVestAmount; // total entitlement\n        uint112 cliffAmount; // how much is released at the cliff\n        uint112 amountWithdrawn; // how much was withdrawn thus far - released at the cliffReleaseTimestamp\n        bool isActive; // whether this claim is active (or revoked)\n    }    \n\n    // Mapping every user address to his/her Claim\n    // Only one Claim possible per address\n    mapping (address => Claim) internal claims;\n\n    // Track the recipients of the vesting\n    address[] internal vestingRecipients;\n\n    // Events:\n    /**\n    @notice Emitted when a founder adds a vesting schedule.\n     */\n    event ClaimCreated(address indexed _recipient, Claim _claim); \n\n    /**\n    @notice Emitted when someone withdraws a vested amount\n    */\n    event Claimed(address indexed _recipient, uint112 _withdrawalAmount); \n\n    /** \n    @notice Emitted when a claim is revoked\n    */\n    event ClaimRevoked(address indexed _recipient, uint112 _numTokensWithheld, uint256 revocationTimestamp, Claim _claim);\n    \n    /** \n    @notice Emitted when admin withdraws.\n    */\n    event AdminWithdrawn(address indexed _recipient, uint112 _amountRequested);\n\n    // \n    /**\n    @notice Construct the contract, taking the ERC20 token to be vested as the parameter.\n    @dev The owner can set the contract in question when creating the contract.\n     */\n    constructor(IERC20 _tokenAddress) {\n        require(address(_tokenAddress) != address(0), \"INVALID_ADDRESS\");\n        tokenAddress = _tokenAddress;\n    }\n\n    /**\n    @notice Basic getter for a claim. \n    @dev Could be using public claims var, but this is cleaner in terms of naming. (getClaim(address) as opposed to claims(address)). \n    @param _recipient - the address for which we fetch the claim.\n     */\n    function getClaim(address _recipient) external view returns (Claim memory) {\n        return claims[_recipient];\n    }\n\n    /**\n    @notice This modifier requires that an user has a claim attached.\n    @dev  To determine this, we check that a claim:\n    * - is active\n    * - start timestamp is nonzero.\n    * These are sufficient conditions because we only ever set startTimestamp in \n    * createClaim, and we never change it. Therefore, startTimestamp will be set\n    * IFF a claim has been created. In addition to that, we need to check\n    * a claim is active (since this is has_*Active*_Claim)\n    */\n    modifier hasActiveClaim(address _recipient) {\n        Claim storage _claim = claims[_recipient];\n        require(_claim.startTimestamp > 0, \"NO_ACTIVE_CLAIM\");\n\n        // We however still need the active check, since (due to the name of the function)\n        // we want to only allow active claims\n        require(_claim.isActive == true, \"NO_ACTIVE_CLAIM\");\n\n        // Save gas, omit further checks\n        // require(_claim.linearVestAmount + _claim.cliffAmount > 0, \"INVALID_VESTED_AMOUNT\");\n        // require(_claim.endTimestamp > 0, \"NO_END_TIMESTAMP\");\n        _;\n    }\n\n    /** \n    @notice Modifier which is opposite hasActiveClaim\n    @dev Requires that all fields are unset\n    */ \n    modifier hasNoClaim(address _recipient) {\n        Claim storage _claim = claims[_recipient];\n        // Start timestamp != 0 is a sufficient condition for a claim to exist\n        // This is because we only ever add claims (or modify startTs) in the createClaim function \n        // Which requires that its input startTimestamp be nonzero\n        // So therefore, a zero value for this indicates the claim does not exist.\n        require(_claim.startTimestamp == 0, \"CLAIM_ALREADY_EXISTS\");\n        \n        // We don't even need to check for active to be unset, since this function only \n        // determines that a claim hasn't been set\n        // require(_claim.isActive == false, \"CLAIM_ALREADY_EXISTS\");\n    \n        // Further checks aren't necessary (to save gas), as they're done at creation time (createClaim)\n        // require(_claim.endTimestamp == 0, \"CLAIM_ALREADY_EXISTS\");\n        // require(_claim.linearVestAmount + _claim.cliffAmount == 0, \"CLAIM_ALREADY_EXISTS\");\n        // require(_claim.amountWithdrawn == 0, \"CLAIM_ALREADY_EXISTS\");\n        _;\n    }\n\n    /**\n    @notice Pure function to calculate the vested amount from a given _claim, at a reference timestamp\n    @param _claim The claim in question\n    @param _referenceTs Timestamp for which we're calculating\n     */\n    function _baseVestedAmount(Claim memory _claim, uint40 _referenceTs) internal pure returns (uint112) {\n        uint112 vestAmt = 0;\n        \n        // the condition to have anything vested is to be active\n        if(_claim.isActive) {\n            // no point of looking past the endTimestamp as nothing should vest afterwards\n            // So if we're past the end, just get the ref frame back to the end\n            if(_referenceTs > _claim.endTimestamp) {\n                _referenceTs = _claim.endTimestamp;\n            }\n\n            // If we're past the cliffReleaseTimestamp, we release the cliffAmount\n            // We don't check here that cliffReleaseTimestamp is after the startTimestamp \n            if(_referenceTs >= _claim.cliffReleaseTimestamp) {\n                vestAmt += _claim.cliffAmount;\n            }\n\n            // Calculate the linearly vested amount - this is relevant only if we're past the schedule start\n            // at _referenceTs == _claim.startTimestamp, the period proportion will be 0 so we don't need to start the calc\n            if(_referenceTs > _claim.startTimestamp) {\n                uint40 currentVestingDurationSecs = _referenceTs - _claim.startTimestamp; // How long since the start\n                // Next, we need to calculated the duration truncated to nearest releaseIntervalSecs\n                uint40 truncatedCurrentVestingDurationSecs = (currentVestingDurationSecs / _claim.releaseIntervalSecs) * _claim.releaseIntervalSecs;\n                uint40 finalVestingDurationSecs = _claim.endTimestamp - _claim.startTimestamp; // length of the interval\n\n                // Calculate the linear vested amount - fraction_of_interval_completed * linearVestedAmount\n                // Since fraction_of_interval_completed is truncatedCurrentVestingDurationSecs / finalVestingDurationSecs, the formula becomes\n                // truncatedCurrentVestingDurationSecs / finalVestingDurationSecs * linearVestAmount, so we can rewrite as below to avoid \n                // rounding errors\n                uint112 linearVestAmount = _claim.linearVestAmount * truncatedCurrentVestingDurationSecs / finalVestingDurationSecs;\n\n                // Having calculated the linearVestAmount, simply add it to the vested amount\n                vestAmt += linearVestAmount;\n            }\n        }\n        \n        // Return the bigger of (vestAmt, _claim.amountWithdrawn)\n        // Rationale: no matter how we calculate the vestAmt, we can never return that less was vested than was already withdrawn.\n        // Case where this could be relevant - If the claim is inactive, vestAmt would be 0, yet if something was already withdrawn \n        // on that claim, we want to return that as vested thus far - as we want the function to be monotonic.\n        return (vestAmt > _claim.amountWithdrawn) ? vestAmt : _claim.amountWithdrawn;\n    }\n\n    /**\n    @notice Calculate the amount vested for a given _recipient at a reference timestamp.\n    @param _recipient - The address for whom we're calculating\n    @param _referenceTs - The timestamp at which we want to calculate the vested amount.\n    @dev Simply call the _baseVestedAmount for the claim in question\n    */\n    function vestedAmount(address _recipient, uint40 _referenceTs) public view returns (uint112) {\n        Claim storage _claim = claims[_recipient];\n        return _baseVestedAmount(_claim, _referenceTs);\n    }\n\n    /**\n    @notice Calculate the total vested at the end of the schedule, by simply feeding in the end timestamp to the function above.\n    @dev This fn is somewhat superfluous, should probably be removed.\n    @param _recipient - The address for whom we're calculating\n     */\n    function finalVestedAmount(address _recipient) public view returns (uint112) {\n        Claim storage _claim = claims[_recipient];\n        return _baseVestedAmount(_claim, _claim.endTimestamp);\n    }\n    \n    /**\n    @notice Calculates how much can we claim, by subtracting the already withdrawn amount from the vestedAmount at this moment.\n    @param _recipient - The address for whom we're calculating\n    */\n    function claimableAmount(address _recipient) external view returns (uint112) {\n        Claim storage _claim = claims[_recipient];\n        return _baseVestedAmount(_claim, uint40(block.timestamp)) - _claim.amountWithdrawn;\n    }\n    \n    /** \n    @notice Return all the addresses that have vesting schedules attached.\n    */ \n    function allVestingRecipients() external view returns (address[] memory) {\n        return vestingRecipients;\n    }\n\n    /** \n    @notice Get the total number of vesting recipients.\n    */\n    function numVestingRecipients() external view returns (uint256) {\n        return vestingRecipients.length;\n    }\n\n    /** \n    @notice Permission-unchecked version of claim creation (no onlyAdmin). Actual logic for create claim, to be run within either createClaim or createClaimBatch.\n    @dev This'll simply check the input parameters, and create the structure verbatim based on passed in parameters.\n    @param _recipient - The address of the recipient of the schedule\n    @param _startTimestamp - The timestamp when the linear vesting starts\n    @param _endTimestamp - The timestamp when the linear vesting ends\n    @param _cliffReleaseTimestamp - The timestamp when the cliff is released (must be <= _startTimestamp, or 0 if no vesting)\n    @param _releaseIntervalSecs - The release interval for the linear vesting. If this is, for example, 60, that means that the linearly vested amount gets released every 60 seconds.\n    @param _linearVestAmount - The total amount to be linearly vested between _startTimestamp and _endTimestamp\n    @param _cliffAmount - The amount released at _cliffReleaseTimestamp. Can be 0 if _cliffReleaseTimestamp is also 0.\n     */\n    function _createClaimUnchecked(\n            address _recipient, \n            uint40 _startTimestamp, \n            uint40 _endTimestamp, \n            uint40 _cliffReleaseTimestamp, \n            uint40 _releaseIntervalSecs, \n            uint112 _linearVestAmount, \n            uint112 _cliffAmount\n                ) private  hasNoClaim(_recipient) {\n\n        require(_recipient != address(0), \"INVALID_ADDRESS\");\n        require(_linearVestAmount + _cliffAmount > 0, \"INVALID_VESTED_AMOUNT\"); // Actually only one of linearvested/cliff amount must be 0, not necessarily both\n        require(_startTimestamp > 0, \"INVALID_START_TIMESTAMP\");\n        // Do we need to check whether _startTimestamp is greater than the current block.timestamp? \n        // Or do we allow schedules that started in the past? \n        // -> Conclusion: we want to allow this, for founders that might have forgotten to add some users, or to avoid issues with transactions not going through because of discoordination between block.timestamp and sender's local time\n        // require(_endTimestamp > 0, \"_endTimestamp must be valid\"); // not necessary because of the next condition (transitively)\n        require(_startTimestamp < _endTimestamp, \"INVALID_END_TIMESTAMP\"); // _endTimestamp must be after _startTimestamp\n        require(_releaseIntervalSecs > 0, \"INVALID_RELEASE_INTERVAL\");\n        require((_endTimestamp - _startTimestamp) % _releaseIntervalSecs == 0, \"INVALID_INTERVAL_LENGTH\");\n\n        // Potential TODO: sanity check, if _linearVestAmount == 0, should we perhaps force that start and end ts are the same?\n\n        // No point in allowing cliff TS without the cliff amount or vice versa.\n        // Both or neither of _cliffReleaseTimestamp and _cliffAmount must be set. If cliff is set, _cliffReleaseTimestamp must be before or at the _startTimestamp\n        require( \n            (\n                _cliffReleaseTimestamp > 0 && \n                _cliffAmount > 0 && \n                _cliffReleaseTimestamp <= _startTimestamp\n            ) || (\n                _cliffReleaseTimestamp == 0 && \n                _cliffAmount == 0\n        ), \"INVALID_CLIFF\");\n\n        Claim memory _claim = Claim({\n            startTimestamp: _startTimestamp,\n            endTimestamp: _endTimestamp,\n            cliffReleaseTimestamp: _cliffReleaseTimestamp,\n            releaseIntervalSecs: _releaseIntervalSecs,\n            cliffAmount: _cliffAmount,\n            linearVestAmount: _linearVestAmount,\n            amountWithdrawn: 0,\n            isActive: true\n        });\n        // Our total allocation is simply the full sum of the two amounts, _cliffAmount + _linearVestAmount\n        // Not necessary to use the more complex logic from _baseVestedAmount\n        uint112 allocatedAmount = _cliffAmount + _linearVestAmount;\n\n        // Still no effects up to this point (and tokenAddress is selected by contract deployer and is immutable), so no reentrancy risk \n        require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, \"INSUFFICIENT_BALANCE\");\n\n        // Done with checks\n\n        // Effects limited to lines below\n        claims[_recipient] = _claim; // store the claim\n        numTokensReservedForVesting += allocatedAmount; // track the allocated amount\n        vestingRecipients.push(_recipient); // add the vesting recipient to the list\n        emit ClaimCreated(_recipient, _claim); // let everyone know\n    }\n\n    /** \n    @notice Create a claim based on the input parameters.\n    @dev This'll simply check the input parameters, and create the structure verbatim based on passed in parameters.\n    @param _recipient - The address of the recipient of the schedule\n    @param _startTimestamp - The timestamp when the linear vesting starts\n    @param _endTimestamp - The timestamp when the linear vesting ends\n    @param _cliffReleaseTimestamp - The timestamp when the cliff is released (must be <= _startTimestamp, or 0 if no vesting)\n    @param _releaseIntervalSecs - The release interval for the linear vesting. If this is, for example, 60, that means that the linearly vested amount gets released every 60 seconds.\n    @param _linearVestAmount - The total amount to be linearly vested between _startTimestamp and _endTimestamp\n    @param _cliffAmount - The amount released at _cliffReleaseTimestamp. Can be 0 if _cliffReleaseTimestamp is also 0.\n     */\n    function createClaim(\n            address _recipient, \n            uint40 _startTimestamp, \n            uint40 _endTimestamp, \n            uint40 _cliffReleaseTimestamp, \n            uint40 _releaseIntervalSecs, \n            uint112 _linearVestAmount, \n            uint112 _cliffAmount\n                ) external onlyAdmin {\n        _createClaimUnchecked(_recipient, _startTimestamp, _endTimestamp, _cliffReleaseTimestamp, _releaseIntervalSecs, _linearVestAmount, _cliffAmount);\n    }\n\n    /**\n    @notice The batch version of the createClaim function. Each argument is an array, and this function simply repeatedly calls the createClaim.\n    \n     */\n    function createClaimsBatch(\n        address[] memory _recipients, \n        uint40[] memory _startTimestamps, \n        uint40[] memory _endTimestamps, \n        uint40[] memory _cliffReleaseTimestamps, \n        uint40[] memory _releaseIntervalsSecs, \n        uint112[] memory _linearVestAmounts, \n        uint112[] memory _cliffAmounts) \n        external onlyAdmin {\n        \n        uint256 length = _recipients.length;\n        require(_startTimestamps.length == length &&\n                _endTimestamps.length == length &&\n                _cliffReleaseTimestamps.length == length &&\n                _releaseIntervalsSecs.length == length &&\n                _linearVestAmounts.length == length &&\n                _cliffAmounts.length == length, \n                \"ARRAY_LENGTH_MISMATCH\"\n        );\n\n        for (uint256 i = 0; i < length; i++) {\n            _createClaimUnchecked(_recipients[i], _startTimestamps[i], _endTimestamps[i], _cliffReleaseTimestamps[i], _releaseIntervalsSecs[i], _linearVestAmounts[i], _cliffAmounts[i]);\n        }\n\n        // No need for separate emit, since createClaim will emit for each claim (and this function is merely a convenience/gas-saver for multiple claims creation)\n    }\n\n    /**\n    @notice Withdraw the full claimable balance.\n    @dev hasActiveClaim throws off anyone without a claim.\n     */\n    function withdraw() hasActiveClaim(_msgSender()) external {\n        // Get the message sender claim - if any\n\n        Claim storage usrClaim = claims[_msgSender()];\n\n        // we can use block.timestamp directly here as reference TS, as the function itself will make sure to cap it to endTimestamp\n        // Conversion of timestamp to uint40 should be safe since 48 bit allows for a lot of years.\n        uint112 allowance = vestedAmount(_msgSender(), uint40(block.timestamp));\n\n        // Make sure we didn't already withdraw more that we're allowed.\n        require(allowance > usrClaim.amountWithdrawn, \"NOTHING_TO_WITHDRAW\");\n\n        // Calculate how much can we withdraw (equivalent to the above inequality)\n        uint112 amountRemaining = allowance - usrClaim.amountWithdrawn;\n\n        // \"Double-entry bookkeeping\"\n        // Carry out the withdrawal by noting the withdrawn amount, and by transferring the tokens.\n        usrClaim.amountWithdrawn += amountRemaining;\n        // Reduce the allocated amount since the following transaction pays out so the \"debt\" gets reduced\n        numTokensReservedForVesting -= amountRemaining;\n        \n        // After the \"books\" are set, transfer the tokens\n        // Reentrancy note - internal vars have been changed by now\n        // Also following Checks-effects-interactions pattern\n        tokenAddress.safeTransfer(_msgSender(), amountRemaining);\n\n        // Let withdrawal known to everyone.\n        emit Claimed(_msgSender(), amountRemaining);\n    }\n\n    /**\n    @notice Admin withdrawal of the unallocated tokens.\n    @param _amountRequested - the amount that we want to withdraw\n     */\n    function withdrawAdmin(uint112 _amountRequested) public onlyAdmin {    \n        // Allow the owner to withdraw any balance not currently tied up in contracts.\n        uint256 amountRemaining = tokenAddress.balanceOf(address(this)) - numTokensReservedForVesting;\n\n        require(amountRemaining >= _amountRequested, \"INSUFFICIENT_BALANCE\");\n\n        // Actually withdraw the tokens\n        // Reentrancy note - this operation doesn't touch any of the internal vars, simply transfers\n        // Also following Checks-effects-interactions pattern\n        tokenAddress.safeTransfer(_msgSender(), _amountRequested);\n\n        // Let the withdrawal known to everyone\n        emit AdminWithdrawn(_msgSender(), _amountRequested);\n    }\n\n\n    /** \n    @notice Allow an Owner to revoke a claim that is already active.\n    @dev The requirement is that a claim exists and that it's active.\n    */ \n    function revokeClaim(address _recipient) external onlyAdmin hasActiveClaim(_recipient) {\n        // Fetch the claim\n        Claim storage _claim = claims[_recipient];\n        // Calculate what the claim should finally vest to\n        uint112 finalVestAmt = finalVestedAmount(_recipient);\n\n        // No point in revoking something that has been fully consumed\n        // so require that there be unconsumed amount\n        require( _claim.amountWithdrawn < finalVestAmt, \"NO_UNVESTED_AMOUNT\");\n\n        // The amount that is \"reclaimed\" is equal to the total allocation less what was already withdrawn\n        uint112 amountRemaining = finalVestAmt - _claim.amountWithdrawn;\n\n        // Deactivate the claim, and release the appropriate amount of tokens\n        _claim.isActive = false;    // This effectively reduces the liability by amountRemaining, so we can reduce the liability numTokensReservedForVesting by that much\n        numTokensReservedForVesting -= amountRemaining; // Reduces the allocation\n\n        // Tell everyone a claim has been revoked.\n        emit ClaimRevoked(_recipient, amountRemaining, uint40(block.timestamp), _claim);\n    }\n\n    /**\n    @notice Withdraw a token which isn't controlled by the vesting contract.\n    @dev This contract controls/vests token at \"tokenAddress\". However, someone might send a different token. \n    To make sure these don't get accidentally trapped, give admin the ability to withdraw them (to their own address).\n    Note that the token to be withdrawn can't be the one at \"tokenAddress\".\n    @param _otherTokenAddress - the token which we want to withdraw\n     */\n    function withdrawOtherToken(IERC20 _otherTokenAddress) external onlyAdmin {\n        require(_otherTokenAddress != tokenAddress, \"INVALID_TOKEN\"); // tokenAddress address is already sure to be nonzero due to constructor\n        uint256 bal = _otherTokenAddress.balanceOf(address(this));\n        require(bal > 0, \"INSUFFICIENT_BALANCE\");\n        _otherTokenAddress.safeTransfer(_msgSender(), bal);\n    }\n}"
}