creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "convex-platform/contracts/contracts/ArbitartorVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   ArbitratorVault\n * @author  ConvexFinance\n * @notice  Hold extra reward tokens on behalf of pools that have the same token as a reward (e.g. stkAAVE fro multiple aave pools)\n * @dev     Sits on top of the STASH to basically handle the re-distribution of rewards to multiple stashes.\n *          Because anyone can call gauge.claim_rewards(address) for the convex staking contract, rewards\n *          could be forced to the wrong pool. Hold tokens here and distribute fairly(or at least more fairly),\n *          to both pools at a later timing.\n */\ncontract ArbitratorVault{\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public operator;\n    address public immutable depositor;\n\n\n    /**\n     * @param  _depositor Booster address\n     */\n    constructor(address _depositor)public\n    {\n        operator = msg.sender;\n        depositor = _depositor;\n    }\n\n    function setOperator(address _op) external {\n        require(msg.sender == operator, \"!auth\");\n        operator = _op;\n    }\n\n    /**\n    * @notice  Permissioned fn to distribute any accrued rewards to a relevant stash\n    * @dev     Only called by operator: ConvexMultisig\n    */\n    function distribute(address _token, uint256[] calldata _toPids, uint256[] calldata _amounts) external {\n       require(msg.sender == operator, \"!auth\");\n\n       for(uint256 i = 0; i < _toPids.length; i++){\n        //get stash from pid\n        (,,,,address stashAddress,bool shutdown) = IDeposit(depositor).poolInfo(_toPids[i]);\n\n        //if sent to a shutdown pool, could get trapped\n        require(shutdown==false,\"pool closed\");\n\n        //transfer\n        IERC20(_token).safeTransfer(stashAddress, _amounts[i]);\n       }\n    }\n\n}"
      },
      "convex-platform/contracts/contracts/Interfaces.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\n\n\ninterface ICurveGauge {\n    function deposit(uint256) external;\n    function balanceOf(address) external view returns (uint256);\n    function withdraw(uint256) external;\n    function claim_rewards() external;\n    function reward_tokens(uint256) external view returns(address);//v2\n    function rewarded_token() external view returns(address);//v1\n    function lp_token() external view returns(address);\n}\n\ninterface ICurveVoteEscrow {\n    function create_lock(uint256, uint256) external;\n    function increase_amount(uint256) external;\n    function increase_unlock_time(uint256) external;\n    function withdraw() external;\n    function smart_wallet_checker() external view returns (address);\n    function commit_smart_wallet_checker(address) external;\n    function apply_smart_wallet_checker() external;\n}\n\ninterface IWalletChecker {\n    function check(address) external view returns (bool);\n    function approveWallet(address) external;\n    function dao() external view returns (address);\n}\n\ninterface IVoting{\n    function vote(uint256, bool, bool) external; //voteId, support, executeIfDecided\n    function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); \n    function vote_for_gauge_weights(address,uint256) external;\n}\n\ninterface IMinter{\n    function mint(address) external;\n}\n\ninterface IStaker{\n    function deposit(address, address) external returns (bool);\n    function withdraw(address) external returns (uint256);\n    function withdraw(address, address, uint256) external returns (bool);\n    function withdrawAll(address, address) external returns (bool);\n    function createLock(uint256, uint256) external returns(bool);\n    function increaseAmount(uint256) external returns(bool);\n    function increaseTime(uint256) external returns(bool);\n    function release() external returns(bool);\n    function claimCrv(address) external returns (uint256);\n    function claimRewards(address) external returns(bool);\n    function claimFees(address,address) external returns (uint256);\n    function setStashAccess(address, bool) external returns (bool);\n    function vote(uint256,address,bool) external returns(bool);\n    function voteGaugeWeight(address,uint256) external returns(bool);\n    function balanceOfPool(address) external view returns (uint256);\n    function operator() external view returns (address);\n    function execute(address _to, uint256 _value, bytes calldata _data) external returns (bool, bytes memory);\n    function setVote(bytes32 hash, bool valid) external;\n    function migrate(address to) external;\n}\n\ninterface IRewards{\n    function stake(address, uint256) external;\n    function stakeFor(address, uint256) external;\n    function withdraw(address, uint256) external;\n    function exit(address) external;\n    function getReward(address) external;\n    function queueNewRewards(uint256) external;\n    function notifyRewardAmount(uint256) external;\n    function addExtraReward(address) external;\n    function extraRewardsLength() external view returns (uint256);\n    function stakingToken() external view returns (address);\n    function rewardToken() external view returns(address);\n    function earned(address account) external view returns (uint256);\n}\n\ninterface IStash{\n    function stashRewards() external returns (bool);\n    function processStash() external returns (bool);\n    function claimRewards() external returns (bool);\n    function initialize(uint256 _pid, address _operator, address _staker, address _gauge, address _rewardFactory) external;\n}\n\ninterface IFeeDistributor {\n    function claimToken(address user, address token) external returns (uint256);\n    function claimTokens(address user, address[] calldata tokens) external returns (uint256[] memory);\n    function getTokenTimeCursor(address token) external view returns (uint256);\n}\n\ninterface ITokenMinter{\n    function mint(address,uint256) external;\n    function burn(address,uint256) external;\n}\n\ninterface IDeposit{\n    function isShutdown() external view returns(bool);\n    function balanceOf(address _account) external view returns(uint256);\n    function totalSupply() external view returns(uint256);\n    function poolInfo(uint256) external view returns(address,address,address,address,address, bool);\n    function rewardClaimed(uint256,address,uint256) external;\n    function withdrawTo(uint256,uint256,address) external;\n    function claimRewards(uint256,address) external returns(bool);\n    function rewardArbitrator() external returns(address);\n    function setGaugeRedirect(uint256 _pid) external returns(bool);\n    function owner() external returns(address);\n    function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns(bool);\n}\n\ninterface ICrvDeposit{\n    function deposit(uint256, bool) external;\n    function lockIncentive() external view returns(uint256);\n}\n\ninterface IRewardFactory{\n    function setAccess(address,bool) external;\n    function CreateCrvRewards(uint256,address,address) external returns(address);\n    function CreateTokenRewards(address,address,address) external returns(address);\n    function activeRewardCount(address) external view returns(uint256);\n    function addActiveReward(address,uint256) external returns(bool);\n    function removeActiveReward(address,uint256) external returns(bool);\n}\n\ninterface IStashFactory{\n    function CreateStash(uint256,address,address,uint256) external returns(address);\n}\n\ninterface ITokenFactory{\n    function CreateDepositToken(address) external returns(address);\n}\n\ninterface IPools{\n    function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool);\n    function forceAddPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool);\n    function shutdownPool(uint256 _pid) external returns(bool);\n    function poolInfo(uint256) external view returns(address,address,address,address,address,bool);\n    function poolLength() external view returns (uint256);\n    function gaugeMap(address) external view returns(bool);\n    function setPoolManager(address _poolM) external;\n}\n\ninterface IVestedEscrow{\n    function fund(address[] calldata _recipient, uint256[] calldata _amount) external returns(bool);\n}\n\ninterface IRewardDeposit {\n    function addReward(address, uint256) external;\n}\n"
      },
      "@openzeppelin/contracts-0.6/math/SafeMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        uint256 c = a + b;\n        if (c < a) return (false, 0);\n        return (true, c);\n    }\n\n    /**\n     * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b > a) return (false, 0);\n        return (true, a - b);\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) return (true, 0);\n        uint256 c = a * b;\n        if (c / a != b) return (false, 0);\n        return (true, c);\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b == 0) return (false, 0);\n        return (true, a / b);\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b == 0) return (false, 0);\n        return (true, a % b);\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c >= a, \"SafeMath: addition overflow\");\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b <= a, \"SafeMath: subtraction overflow\");\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (a == 0) return 0;\n        uint256 c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b > 0, \"SafeMath: division by zero\");\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b > 0, \"SafeMath: modulo by zero\");\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b <= a, errorMessage);\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryDiv}.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        return a % b;\n    }\n}\n"
      },
      "@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "@openzeppelin/contracts-0.6/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.2 <0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n        (bool success, ) = recipient.call{ value: amount }(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain`call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n      return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: value }(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                // solhint-disable-next-line no-inline-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using SafeMath for uint256;\n    using Address for address;\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        // solhint-disable-next-line max-line-length\n        require((value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).add(value);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) { // Return data is optional\n            // solhint-disable-next-line max-line-length\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/VoterProxy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   VoterProxy\n * @author  ConvexFinance\n * @notice  VoterProxy whitelisted in the curve SmartWalletWhitelist that\n *          participates in Curve governance. Also handles all deposits since this is \n *          the address that has the voting power.\n */\ncontract VoterProxy {\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public mintr;\n    address public immutable crv;\n    address public immutable crvBpt;\n\n    address public immutable escrow;\n    address public gaugeController;\n    address public rewardDeposit;\n    address public withdrawer;\n\n    address public owner;\n    address public operator;\n    address public depositor;\n    \n    mapping (address => bool) private stashPool;\n    mapping (address => bool) private protectedTokens;\n    mapping (bytes32 => bool) private votes;\n\n    bytes4 constant internal EIP1271_MAGIC_VALUE = 0x1626ba7e;\n\n    event VoteSet(bytes32 hash, bool valid);\n\n    /**\n     * @param _mintr            CRV minter\n     * @param _crv              CRV Token address\n     * @param _crvBpt           CRV:ETH 80-20 BPT Token address\n     * @param _escrow           Curve Voting escrow contract\n     * @param _gaugeController  Curve Gauge Controller\n     *                          Controls liquidity gauges and the issuance of coins through the gauges\n     */\n    constructor(\n        address _mintr,\n        address _crv,\n        address _crvBpt,\n        address _escrow,\n        address _gaugeController\n    ) public {\n        mintr = _mintr; \n        crv = _crv;\n        crvBpt = _crvBpt;\n        escrow = _escrow;\n        gaugeController = _gaugeController;\n        owner = msg.sender;\n\n        protectedTokens[_crv] = true;\n        protectedTokens[_crvBpt] = true;\n    }\n\n    function getName() external pure returns (string memory) {\n        return \"BalancerVoterProxy\";\n    }\n\n    function setOwner(address _owner) external {\n        require(msg.sender == owner, \"!auth\");\n        owner = _owner;\n    }\n\n    /**\n     * @notice Allows dao to set the reward withdrawal address\n     * @param _withdrawer Whitelisted withdrawer\n     * @param _rewardDeposit Distributor address\n     */\n    function setRewardDeposit(address _withdrawer, address _rewardDeposit) external {\n        require(msg.sender == owner, \"!auth\");\n        withdrawer = _withdrawer;\n        rewardDeposit = _rewardDeposit;\n    }\n\n    /**\n     * @notice Allows dao to set the external system config, should it change in the future\n     * @param _gaugeController External gauge controller address\n     * @param _mintr Token minter address for claiming rewards\n     */\n    function setSystemConfig(address _gaugeController, address _mintr) external returns (bool) {\n        require(msg.sender == owner, \"!auth\");\n        gaugeController = _gaugeController;\n        mintr = _mintr;\n        return true;\n    }\n\n    /**\n     * @notice Set the operator of the VoterProxy\n     * @param _operator Address of the operator (Booster)\n     */\n    function setOperator(address _operator) external {\n        require(msg.sender == owner, \"!auth\");\n        require(operator == address(0) || IDeposit(operator).isShutdown() == true, \"needs shutdown\");\n        \n        operator = _operator;\n    }\n\n    /**\n     * @notice Set the depositor of the VoterProxy\n     * @param _depositor Address of the depositor (CrvDepositor)\n     */\n    function setDepositor(address _depositor) external {\n        require(msg.sender == owner, \"!auth\");\n\n        depositor = _depositor;\n    }\n\n    function setStashAccess(address _stash, bool _status) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        if(_stash != address(0)){\n            stashPool[_stash] = _status;\n        }\n        return true;\n    }\n\n    /**\n     * @notice Save a vote hash so when snapshot.org asks this contract if \n     *          a vote signature is valid we are able to check for a valid hash\n     *          and return the appropriate response inline with EIP 1721\n     * @param _hash  Hash of vote signature that was sent to snapshot.org\n     * @param _valid Is the hash valid\n     */\n    function setVote(bytes32 _hash, bool _valid) external {\n        require(msg.sender == operator, \"!auth\");\n        votes[_hash] = _valid;\n        emit VoteSet(_hash, _valid);\n    }\n\n    /**\n     * @notice  Verifies that the hash is valid\n     * @dev     Snapshot Hub will call this function when a vote is submitted using\n     *          snapshot.js on behalf of this contract. Snapshot Hub will call this\n     *          function with the hash and the signature of the vote that was cast.\n     * @param _hash Hash of the message that was sent to Snapshot Hub to cast a vote\n     * @return EIP1271 magic value if the signature is value \n     */\n    function isValidSignature(bytes32 _hash, bytes memory) public view returns (bytes4) {\n        if(votes[_hash]) {\n            return EIP1271_MAGIC_VALUE;\n        } else {\n            return 0xffffffff;\n        }  \n    }\n\n    /**\n     * @notice  Deposit tokens into the Curve Gauge\n     * @dev     Only can be called by the operator (Booster) once this contract has been\n     *          whitelisted by the Curve DAO\n     * @param _token  Deposit LP token address\n     * @param _gauge  Gauge contract to deposit to \n     */ \n    function deposit(address _token, address _gauge) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        if(protectedTokens[_token] == false){\n            protectedTokens[_token] = true;\n        }\n        if(protectedTokens[_gauge] == false){\n            protectedTokens[_gauge] = true;\n        }\n        uint256 balance = IERC20(_token).balanceOf(address(this));\n        if (balance > 0) {\n            IERC20(_token).safeApprove(_gauge, 0);\n            IERC20(_token).safeApprove(_gauge, balance);\n            ICurveGauge(_gauge).deposit(balance);\n        }\n        return true;\n    }\n\n    /**\n     * @notice  Withdraw ERC20 tokens that have been distributed as extra rewards\n     * @dev     Tokens shouldn't end up here if they can help it. However, dao can\n     *          set a withdrawer that can process these to some ExtraRewardDistribution.\n     */\n    function withdraw(IERC20 _asset) external returns (uint256 balance) {\n        require(msg.sender == withdrawer, \"!auth\");\n        require(protectedTokens[address(_asset)] == false, \"protected\");\n\n        balance = _asset.balanceOf(address(this));\n        _asset.safeApprove(rewardDeposit, 0);\n        _asset.safeApprove(rewardDeposit, balance);\n        IRewardDeposit(rewardDeposit).addReward(address(_asset), balance);\n        return balance;\n    }\n\n    /**\n     * @notice  Withdraw LP tokens from a gauge \n     * @dev     Only callable by the operator \n     * @param _token    LP token address\n     * @param _gauge    Gauge for this LP token\n     * @param _amount   Amount of LP token to withdraw\n     */\n    function withdraw(address _token, address _gauge, uint256 _amount) public returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        uint256 _balance = IERC20(_token).balanceOf(address(this));\n        if (_balance < _amount) {\n            _amount = _withdrawSome(_gauge, _amount.sub(_balance));\n            _amount = _amount.add(_balance);\n        }\n        IERC20(_token).safeTransfer(msg.sender, _amount);\n        return true;\n    }\n\n    /**\n     * @notice  Withdraw all LP tokens from a gauge \n     * @dev     Only callable by the operator \n     * @param _token  LP token address\n     * @param _gauge  Gauge for this LP token\n     */\n    function withdrawAll(address _token, address _gauge) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        uint256 amount = balanceOfPool(_gauge).add(IERC20(_token).balanceOf(address(this)));\n        withdraw(_token, _gauge, amount);\n        return true;\n    }\n\n    function _withdrawSome(address _gauge, uint256 _amount) internal returns (uint256) {\n        ICurveGauge(_gauge).withdraw(_amount);\n        return _amount;\n    }\n    \n    \n    /**\n     * @notice  Lock CRV in Curve's voting escrow contract\n     * @dev     Called by the CrvDepositor contract\n     * @param _value      Amount of crv to lock\n     * @param _unlockTime Timestamp to unlock (max is 4 years)\n     */\n    function createLock(uint256 _value, uint256 _unlockTime) external returns(bool){\n        require(msg.sender == depositor, \"!auth\");\n        IERC20(crvBpt).safeApprove(escrow, 0);\n        IERC20(crvBpt).safeApprove(escrow, _value);\n        ICurveVoteEscrow(escrow).create_lock(_value, _unlockTime);\n        return true;\n    }\n  \n    /**\n     * @notice Called by the CrvDepositor to increase amount of locked curve\n     */\n    function increaseAmount(uint256 _value) external returns(bool){\n        require(msg.sender == depositor, \"!auth\");\n        IERC20(crvBpt).safeApprove(escrow, 0);\n        IERC20(crvBpt).safeApprove(escrow, _value);\n        ICurveVoteEscrow(escrow).increase_amount(_value);\n        return true;\n    }\n\n    /**\n     * @notice Called by the CrvDepositor to increase unlocked time of curve\n     * @param _value Timestamp to increase locking to\n     */\n    function increaseTime(uint256 _value) external returns(bool){\n        require(msg.sender == depositor, \"!auth\");\n        ICurveVoteEscrow(escrow).increase_unlock_time(_value);\n        return true;\n    }\n\n    /**\n     * @notice  Withdraw all CRV from Curve's voting escrow contract\n     * @dev     Only callable by CrvDepositor and can only withdraw if lock has expired\n     */\n    function release() external returns(bool){\n        require(msg.sender == depositor, \"!auth\");\n        ICurveVoteEscrow(escrow).withdraw();\n        return true;\n    }\n\n    /**\n     * @notice Vote on CRV DAO for proposal\n     */\n    function vote(uint256 _voteId, address _votingAddress, bool _support) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        IVoting(_votingAddress).vote(_voteId,_support,false);\n        return true;\n    }\n\n    /**\n     * @notice Vote for a single gauge weight via the controller\n     */\n    function voteGaugeWeight(address _gauge, uint256 _weight) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n\n        //vote\n        IVoting(gaugeController).vote_for_gauge_weights(_gauge, _weight);\n        return true;\n    }\n\n    /**\n     * @notice  Claim CRV from Curve\n     * @dev     Claim CRV for LP token staking from the CRV minter contract\n     */\n    function claimCrv(address _gauge) external returns (uint256){\n        require(msg.sender == operator, \"!auth\");\n        \n        uint256 _balance = 0;\n        try IMinter(mintr).mint(_gauge){\n            _balance = IERC20(crv).balanceOf(address(this));\n            IERC20(crv).safeTransfer(operator, _balance);\n        }catch{}\n\n        return _balance;\n    }\n\n    /**\n     * @notice  Claim extra rewards from gauge\n     * @dev     Called by operator (Booster) to claim extra rewards \n     */\n    function claimRewards(address _gauge) external returns(bool){\n        require(msg.sender == operator, \"!auth\");\n        ICurveGauge(_gauge).claim_rewards();\n        return true;\n    }\n\n    /**\n     * @notice  Claim fees (3crv) from staking lp tokens\n     * @dev     Only callable by the operator Booster\n     * @param _distroContract   Fee distribution contract\n     * @param _token            LP token to claim fees for\n     */\n    function claimFees(address _distroContract, address _token) external returns (uint256){\n        require(msg.sender == operator, \"!auth\");\n        IFeeDistributor(_distroContract).claimToken(address(this), _token);\n        uint256 _balance = IERC20(_token).balanceOf(address(this));\n        IERC20(_token).safeTransfer(operator, _balance);\n        return _balance;\n    }    \n\n    function balanceOfPool(address _gauge) public view returns (uint256) {\n        return ICurveGauge(_gauge).balanceOf(address(this));\n    }\n\n    function execute(\n        address _to,\n        uint256 _value,\n        bytes calldata _data\n    ) external returns (bool, bytes memory) {\n        require(msg.sender == operator,\"!auth\");\n\n        (bool success, bytes memory result) = _to.call{value:_value}(_data);\n        require(success, \"!success\");\n\n        return (success, result);\n    }\n\n}\n"
      },
      "convex-platform/contracts/contracts/TokenFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./DepositToken.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   TokenFactory\n * @author  ConvexFinance\n * @notice  Token factory used to create Deposit Tokens. These are the tokenized\n *          pool deposit tokens e.g cvx3crv\n */\ncontract TokenFactory {\n    using Address for address;\n\n    address public immutable operator;\n    string public namePostfix;\n    string public symbolPrefix;\n\n    event DepositTokenCreated(address token, address lpToken);\n\n    /**\n     * @param _operator         Operator is Booster\n     * @param _namePostfix      Postfixes lpToken name\n     * @param _symbolPrefix     Prefixed lpToken symbol\n     */\n    constructor(\n        address _operator,\n        string memory _namePostfix,\n        string memory _symbolPrefix\n    ) public {\n        operator = _operator;\n        namePostfix = _namePostfix;\n        symbolPrefix = _symbolPrefix;\n    }\n\n    function CreateDepositToken(address _lptoken) external returns(address){\n        require(msg.sender == operator, \"!authorized\");\n\n        DepositToken dtoken = new DepositToken(operator,_lptoken,namePostfix,symbolPrefix);\n        emit DepositTokenCreated(address(dtoken), _lptoken);\n        return address(dtoken);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/DepositToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/ERC20.sol\";\n\n\n/**\n * @title   DepositToken\n * @author  ConvexFinance\n * @notice  Simply creates a token that can be minted and burned from the operator\n */\ncontract DepositToken is ERC20 {\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public operator;\n\n    /**\n     * @param _operator         Booster\n     * @param _lptoken          Underlying LP token for deposits\n     * @param _namePostfix      Postfixes lpToken name\n     * @param _symbolPrefix     Prefixed lpToken symbol\n     */\n    constructor(\n        address _operator,\n        address _lptoken,\n        string memory _namePostfix,\n        string memory _symbolPrefix\n    )\n        public\n        ERC20(\n             string(\n                abi.encodePacked(ERC20(_lptoken).name(), _namePostfix)\n            ),\n            string(abi.encodePacked(_symbolPrefix, ERC20(_lptoken).symbol()))\n        )\n    {\n        operator =  _operator;\n    }\n    \n    function mint(address _to, uint256 _amount) external {\n        require(msg.sender == operator, \"!authorized\");\n        \n        _mint(_to, _amount);\n    }\n\n    function burn(address _from, uint256 _amount) external {\n        require(msg.sender == operator, \"!authorized\");\n        \n        _burn(_from, _amount);\n    }\n\n}\n"
      },
      "@openzeppelin/contracts-0.6/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20 {\n    using SafeMath for uint256;\n\n    mapping (address => uint256) private _balances;\n\n    mapping (address => mapping (address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n    uint8 private _decimals;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with\n     * a default value of 18.\n     *\n     * To select a different value for {decimals}, use {_setupDecimals}.\n     *\n     * All three of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor (string memory name_, string memory symbol_) public {\n        _name = name_;\n        _symbol = symbol_;\n        _decimals = 18;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is\n     * called.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return _decimals;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n        _transfer(_msgSender(), recipient, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        _approve(_msgSender(), spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * Requirements:\n     *\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``sender``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {\n        _transfer(sender, recipient, amount);\n        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, \"ERC20: transfer amount exceeds allowance\"));\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, \"ERC20: decreased allowance below zero\"));\n        return true;\n    }\n\n    /**\n     * @dev Moves tokens `amount` from `sender` to `recipient`.\n     *\n     * This is internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(address sender, address recipient, uint256 amount) internal virtual {\n        require(sender != address(0), \"ERC20: transfer from the zero address\");\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(sender, recipient, amount);\n\n        _balances[sender] = _balances[sender].sub(amount, \"ERC20: transfer amount exceeds balance\");\n        _balances[recipient] = _balances[recipient].add(amount);\n        emit Transfer(sender, recipient, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply = _totalSupply.add(amount);\n        _balances[account] = _balances[account].add(amount);\n        emit Transfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n        _totalSupply = _totalSupply.sub(amount);\n        emit Transfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Sets {decimals} to a value other than the default one of 18.\n     *\n     * WARNING: This function should only be called from the constructor. Most\n     * applications that interact with token contracts will not expect\n     * {decimals} to ever change, and may work incorrectly if it does.\n     */\n    function _setupDecimals(uint8 decimals_) internal virtual {\n        _decimals = decimals_;\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be to transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }\n}\n"
      },
      "@openzeppelin/contracts-0.6/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address payable) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes memory) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/StashFactoryV2.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/IProxyFactory.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   StashFactoryV2\n * @author  ConvexFinance\n * @notice  Factory to deploy reward stash contracts that handle extra rewards\n */\ncontract StashFactoryV2 {\n    using Address for address;\n\n    bytes4 private constant rewarded_token = 0x16fa50b1; //rewarded_token()\n    bytes4 private constant reward_tokens = 0x54c49fe9; //reward_tokens(uint256)\n    bytes4 private constant rewards_receiver = 0x01ddabf1; //rewards_receiver(address)\n\n    address public immutable operator;\n    address public immutable rewardFactory;\n    address public immutable proxyFactory;\n\n    address public v1Implementation;\n    address public v2Implementation;\n    address public v3Implementation;\n\n    event StashCreated(address stash, uint256 stashVersion);\n\n    /**\n     * @param _operator       Operator is Booster\n     * @param _rewardFactory  Factory that creates reward contract that are \n     *                        VirtualBalanceRewardPool's used for extra pool rewards\n     * @param _proxyFactory   Deploy proxies with stash implementation\n     */\n    constructor(address _operator, address _rewardFactory, address _proxyFactory) public {\n        operator = _operator;\n        rewardFactory = _rewardFactory;\n        proxyFactory = _proxyFactory;\n    }\n\n    function setImplementation(address _v1, address _v2, address _v3) external{\n        require(msg.sender == IDeposit(operator).owner(),\"!auth\");\n\n        v1Implementation = _v1;\n        v2Implementation = _v2;\n        v3Implementation = _v3;\n    }\n\n    //Create a stash contract for the given gauge.\n    //function calls are different depending on the version of curve gauges so determine which stash type is needed\n    function CreateStash(uint256 _pid, address _gauge, address _staker, uint256 _stashVersion) external returns(address){\n        require(msg.sender == operator, \"!authorized\");\n        require(_gauge != address(0), \"!gauge\");\n\n        if(_stashVersion == uint256(3) && IsV3(_gauge)){\n            //v3\n            require(v3Implementation!=address(0),\"0 impl\");\n            address stash = IProxyFactory(proxyFactory).clone(v3Implementation);\n            IStash(stash).initialize(_pid,operator,_staker,_gauge,rewardFactory);\n            emit StashCreated(stash, _stashVersion);\n            return stash;\n        }else if(_stashVersion == uint256(1) && IsV1(_gauge)){\n            //v1\n            require(v1Implementation!=address(0),\"0 impl\");\n            address stash = IProxyFactory(proxyFactory).clone(v1Implementation);\n            IStash(stash).initialize(_pid,operator,_staker,_gauge,rewardFactory);\n            emit StashCreated(stash, _stashVersion);\n            return stash;\n        }else if(_stashVersion == uint256(2) && !IsV3(_gauge) && IsV2(_gauge)){\n            //v2\n            require(v2Implementation!=address(0),\"0 impl\");\n            address stash = IProxyFactory(proxyFactory).clone(v2Implementation);\n            IStash(stash).initialize(_pid,operator,_staker,_gauge,rewardFactory);\n            emit StashCreated(stash, _stashVersion);\n            return stash;\n        }\n        bool isV1 = IsV1(_gauge);\n        bool isV2 = IsV2(_gauge);\n        bool isV3 = IsV3(_gauge);\n        require(!isV1 && !isV2 && !isV3,\"stash version mismatch\");\n        return address(0);\n    }\n\n    function IsV1(address _gauge) private returns(bool){\n        bytes memory data = abi.encode(rewarded_token);\n        (bool success,) = _gauge.call(data);\n        return success;\n    }\n\n    function IsV2(address _gauge) private returns(bool){\n        bytes memory data = abi.encodeWithSelector(reward_tokens,uint256(0));\n        (bool success,) = _gauge.call(data);\n        return success;\n    }\n\n    function IsV3(address _gauge) private returns(bool){\n        bytes memory data = abi.encodeWithSelector(rewards_receiver,address(0));\n        (bool success,) = _gauge.call(data);\n        return success;\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/interfaces/IProxyFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\ninterface IProxyFactory {\n    function clone(address _target) external returns(address);\n}"
      },
      "convex-platform/contracts/contracts/RewardHook.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\n\n\n/**\n * @title   RewardHook\n * @author  ConvexFinance\n * @notice  Example Reward hook for stash\n * @dev     ExtraRewardStash contracts call this hook if it is set. This hook\n *          can be used to pull rewards during a claim. For example pulling\n *          rewards from master chef.\n */\ncontract RewardHook{\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n\n    address public immutable stash;\n    address public immutable rewardToken;\n\n\n    /**\n     * @param _stash    Address of the reward stash\n     * @param _reward   Reward token\n     */\n    constructor(address _stash, address _reward) public {\n        stash = _stash;\n        rewardToken = _reward;\n    }\n\n\n    /**\n     * @dev Called when claimRewards is called in ExtraRewardStash can implement\n     *      logic to pull rewards i.e from a master chef contract. This is just an example\n     *      and assumes rewards are just sent directly to this hook contract\n     */\n    function onRewardClaim() external{\n\n        //get balance\n        uint256 bal = IERC20(rewardToken).balanceOf(address(this));\n\n        //send\n        IERC20(rewardToken).safeTransfer(stash,bal);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n/**\n *Submitted for verification at Etherscan.io on 2020-07-17\n */\n\n/*\n   ____            __   __        __   _\n  / __/__ __ ___  / /_ / /  ___  / /_ (_)__ __\n _\\ \\ / // // _ \\/ __// _ \\/ -_)/ __// / \\ \\ /\n/___/ \\_, //_//_/\\__//_//_/\\__/ \\__//_/ /_\\_\\\n     /___/\n\n* Synthetix: VirtualBalanceRewardPool.sol\n*\n* Docs: https://docs.synthetix.io/\n*\n*\n* MIT License\n* ===========\n*\n* Copyright (c) 2020 Synthetix\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all\n* copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n*/\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/MathUtil.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n\nabstract contract VirtualBalanceWrapper {\n    using SafeMath for uint256;\n    using SafeERC20 for IERC20;\n\n    IDeposit public immutable deposits;\n\n    constructor(address deposit_) internal {\n        deposits = IDeposit(deposit_);\n    }\n\n    function totalSupply() public view returns (uint256) {\n        return deposits.totalSupply();\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        return deposits.balanceOf(account);\n    }\n}\n\n/**\n * @title   VirtualBalanceRewardPool\n * @author  ConvexFinance\n * @notice  Reward pool used for ExtraRewards in Booster lockFees (3crv) and\n *          Extra reward stashes\n * @dev     The rewards are sent to this contract for distribution to stakers. This\n *          contract does not hold any of the staking tokens it just maintains a virtual\n *          balance of what a user has staked in the staking pool (BaseRewardPool).\n *          For example the Booster sends veCRV fees (3Crv) to a VirtualBalanceRewardPool\n *          which tracks the virtual balance of cxvCRV stakers and distributes their share\n *          of 3Crv rewards\n */\ncontract VirtualBalanceRewardPool is VirtualBalanceWrapper {\n    using SafeERC20 for IERC20;\n    \n    IERC20 public immutable rewardToken;\n    uint256 public constant duration = 7 days;\n\n    address public immutable operator;\n\n    uint256 public periodFinish = 0;\n    uint256 public rewardRate = 0;\n    uint256 public lastUpdateTime;\n    uint256 public rewardPerTokenStored;\n    uint256 public queuedRewards = 0;\n    uint256 public currentRewards = 0;\n    uint256 public historicalRewards = 0;\n    uint256 public constant newRewardRatio = 830;\n    mapping(address => uint256) public userRewardPerTokenPaid;\n    mapping(address => uint256) public rewards;\n\n    event RewardAdded(uint256 reward);\n    event Staked(address indexed user, uint256 amount);\n    event Withdrawn(address indexed user, uint256 amount);\n    event RewardPaid(address indexed user, uint256 reward);\n\n    /**\n     * @param deposit_  Parent deposit pool e.g cvxCRV staking in BaseRewardPool\n     * @param reward_   The rewards token e.g 3Crv\n     * @param op_       Operator contract (Booster)\n     */\n    constructor(\n        address deposit_,\n        address reward_,\n        address op_\n    ) public VirtualBalanceWrapper(deposit_) {\n        rewardToken = IERC20(reward_);\n        operator = op_;\n    }\n\n\n    /**\n     * @notice Update rewards earned by this account\n     */\n    modifier updateReward(address account) {\n        rewardPerTokenStored = rewardPerToken();\n        lastUpdateTime = lastTimeRewardApplicable();\n        if (account != address(0)) {\n            rewards[account] = earned(account);\n            userRewardPerTokenPaid[account] = rewardPerTokenStored;\n        }\n        _;\n    }\n\n    function lastTimeRewardApplicable() public view returns (uint256) {\n        return MathUtil.min(block.timestamp, periodFinish);\n    }\n\n    function rewardPerToken() public view returns (uint256) {\n        if (totalSupply() == 0) {\n            return rewardPerTokenStored;\n        }\n        return\n            rewardPerTokenStored.add(\n                lastTimeRewardApplicable()\n                    .sub(lastUpdateTime)\n                    .mul(rewardRate)\n                    .mul(1e18)\n                    .div(totalSupply())\n            );\n    }\n\n    function earned(address account) public view returns (uint256) {\n        return\n            balanceOf(account)\n                .mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))\n                .div(1e18)\n                .add(rewards[account]);\n    }\n\n    /**\n     * @notice  Update reward, emit, call linked reward's stake\n     * @dev     Callable by the deposits address which is the BaseRewardPool\n     *          this updates the virtual balance of this user as this contract doesn't\n     *          actually hold any staked tokens it just diributes reward tokens\n     */\n    function stake(address _account, uint256 amount)\n        external\n        updateReward(_account)\n    {\n        require(msg.sender == address(deposits), \"!authorized\");\n       // require(amount > 0, 'VirtualDepositRewardPool: Cannot stake 0');\n        emit Staked(_account, amount);\n    }\n\n    /**\n     * @notice  Withdraw stake and update reward, emit, call linked reward's stake\n     * @dev     See stake\n     */\n    function withdraw(address _account, uint256 amount)\n        public\n        updateReward(_account)\n    {\n        require(msg.sender == address(deposits), \"!authorized\");\n        //require(amount > 0, 'VirtualDepositRewardPool : Cannot withdraw 0');\n\n        emit Withdrawn(_account, amount);\n    }\n\n    /**\n     * @notice  Get rewards for this account\n     * @dev     This can be called directly but it is usually called by the\n     *          BaseRewardPool getReward when the BaseRewardPool loops through\n     *          it's extraRewards array calling getReward on all of them\n     */\n    function getReward(address _account) public updateReward(_account){\n        uint256 reward = earned(_account);\n        if (reward > 0) {\n            rewards[_account] = 0;\n            rewardToken.safeTransfer(_account, reward);\n            emit RewardPaid(_account, reward);\n        }\n    }\n\n    function getReward() external{\n        getReward(msg.sender);\n    }\n\n    function donate(uint256 _amount) external returns(bool){\n        IERC20(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);\n        queuedRewards = queuedRewards.add(_amount);\n    }\n\n    function queueNewRewards(uint256 _rewards) external{\n        require(msg.sender == operator, \"!authorized\");\n\n        _rewards = _rewards.add(queuedRewards);\n\n        if (block.timestamp >= periodFinish) {\n            notifyRewardAmount(_rewards);\n            queuedRewards = 0;\n            return;\n        }\n\n        //et = now - (finish-duration)\n        uint256 elapsedTime = block.timestamp.sub(periodFinish.sub(duration));\n        //current at now: rewardRate * elapsedTime\n        uint256 currentAtNow = rewardRate * elapsedTime;\n        uint256 queuedRatio = currentAtNow.mul(1000).div(_rewards);\n        if(queuedRatio < newRewardRatio){\n            notifyRewardAmount(_rewards);\n            queuedRewards = 0;\n        }else{\n            queuedRewards = _rewards;\n        }\n    }\n\n    function notifyRewardAmount(uint256 reward)\n        internal\n        updateReward(address(0))\n    {\n        historicalRewards = historicalRewards.add(reward);\n        if (block.timestamp >= periodFinish) {\n            rewardRate = reward.div(duration);\n        } else {\n            uint256 remaining = periodFinish.sub(block.timestamp);\n            uint256 leftover = remaining.mul(rewardRate);\n            reward = reward.add(leftover);\n            rewardRate = reward.div(duration);\n        }\n        currentRewards = reward;\n        lastUpdateTime = block.timestamp;\n        periodFinish = block.timestamp.add(duration);\n        emit RewardAdded(reward);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/interfaces/MathUtil.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUtil {\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n}"
      },
      "convex-platform/contracts/contracts/BaseRewardPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n/**\n *Submitted for verification at Etherscan.io on 2020-07-17\n */\n\n/*\n   ____            __   __        __   _\n  / __/__ __ ___  / /_ / /  ___  / /_ (_)__ __\n _\\ \\ / // // _ \\/ __// _ \\/ -_)/ __// / \\ \\ /\n/___/ \\_, //_//_/\\__//_//_/\\__/ \\__//_/ /_\\_\\\n     /___/\n\n* Synthetix: BaseRewardPool.sol\n*\n* Docs: https://docs.synthetix.io/\n*\n*\n* MIT License\n* ===========\n*\n* Copyright (c) 2020 Synthetix\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all\n* copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n*/\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/MathUtil.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n\n/**\n * @title   BaseRewardPool\n * @author  Synthetix -> ConvexFinance\n * @notice  Unipool rewards contract that is re-deployed from rFactory for each staking pool.\n * @dev     Changes made here by ConvexFinance are to do with the delayed reward allocation. Curve is queued for\n *          rewards and the distribution only begins once the new rewards are sufficiently large, or the epoch\n *          has ended. Additionally, enables hooks for `extraRewards` that can be enabled at any point to\n *          distribute a child reward token (i.e. a secondary one from Curve, or a seperate one).\n */\ncontract BaseRewardPool {\n     using SafeMath for uint256;\n    using SafeERC20 for IERC20;\n\n    IERC20 public immutable rewardToken;\n    IERC20 public immutable stakingToken;\n    uint256 public constant duration = 7 days;\n\n    address public immutable operator;\n    address public immutable rewardManager;\n\n    uint256 public immutable pid;\n    uint256 public periodFinish = 0;\n    uint256 public rewardRate = 0;\n    uint256 public lastUpdateTime;\n    uint256 public rewardPerTokenStored;\n    uint256 public queuedRewards = 0;\n    uint256 public currentRewards = 0;\n    uint256 public historicalRewards = 0;\n    uint256 public constant newRewardRatio = 830;\n    uint256 private _totalSupply;\n    mapping(address => uint256) public userRewardPerTokenPaid;\n    mapping(address => uint256) public rewards;\n    mapping(address => uint256) private _balances;\n\n    address[] public extraRewards;\n\n    event RewardAdded(uint256 reward);\n    event Staked(address indexed user, uint256 amount);\n    event Withdrawn(address indexed user, uint256 amount);\n    event RewardPaid(address indexed user, uint256 reward);\n\n    /**\n     * @dev This is called directly from RewardFactory\n     * @param pid_           Effectively the pool identifier - used in the Booster\n     * @param stakingToken_  Pool LP token\n     * @param rewardToken_   Crv\n     * @param operator_      Booster\n     * @param rewardManager_ RewardFactory\n     */\n    constructor(\n        uint256 pid_,\n        address stakingToken_,\n        address rewardToken_,\n        address operator_,\n        address rewardManager_\n    ) public {\n        pid = pid_;\n        stakingToken = IERC20(stakingToken_);\n        rewardToken = IERC20(rewardToken_);\n        operator = operator_;\n        rewardManager = rewardManager_;\n    }\n\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    function balanceOf(address account) public view virtual returns (uint256) {\n        return _balances[account];\n    }\n\n    function extraRewardsLength() external view returns (uint256) {\n        return extraRewards.length;\n    }\n\n    function addExtraReward(address _reward) external returns(bool){\n        require(msg.sender == rewardManager, \"!authorized\");\n        require(_reward != address(0),\"!reward setting\");\n        \n        if(extraRewards.length >= 12){\n            return false;\n        }\n        \n        extraRewards.push(_reward);\n        return true;\n    }\n    function clearExtraRewards() external{\n        require(msg.sender == rewardManager, \"!authorized\");\n        delete extraRewards;\n    }\n\n    modifier updateReward(address account) {\n        rewardPerTokenStored = rewardPerToken();\n        lastUpdateTime = lastTimeRewardApplicable();\n        if (account != address(0)) {\n            rewards[account] = earned(account);\n            userRewardPerTokenPaid[account] = rewardPerTokenStored;\n        }\n        _;\n    }\n\n    function lastTimeRewardApplicable() public view returns (uint256) {\n        return MathUtil.min(block.timestamp, periodFinish);\n    }\n\n    function rewardPerToken() public view returns (uint256) {\n        if (totalSupply() == 0) {\n            return rewardPerTokenStored;\n        }\n        return\n            rewardPerTokenStored.add(\n                lastTimeRewardApplicable()\n                    .sub(lastUpdateTime)\n                    .mul(rewardRate)\n                    .mul(1e18)\n                    .div(totalSupply())\n            );\n    }\n\n    function earned(address account) public view returns (uint256) {\n        return\n            balanceOf(account)\n                .mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))\n                .div(1e18)\n                .add(rewards[account]);\n    }\n\n    function stake(uint256 _amount)\n        public \n        returns(bool)\n    {\n        _processStake(_amount, msg.sender);\n\n        stakingToken.safeTransferFrom(msg.sender, address(this), _amount);\n        emit Staked(msg.sender, _amount);\n\n        return true;\n    }\n\n    function stakeAll() external returns(bool){\n        uint256 balance = stakingToken.balanceOf(msg.sender);\n        stake(balance);\n        return true;\n    }\n\n    function stakeFor(address _for, uint256 _amount)\n        public\n        returns(bool)\n    {\n        _processStake(_amount, _for);\n\n        //take away from sender\n        stakingToken.safeTransferFrom(msg.sender, address(this), _amount);\n        emit Staked(_for, _amount);\n        \n        return true;\n    }\n\n    /**\n     * @dev Generic internal staking function that basically does 3 things: update rewards based\n     *      on previous balance, trigger also on any child contracts, then update balances.\n     * @param _amount    Units to add to the users balance\n     * @param _receiver  Address of user who will receive the stake\n     */\n    function _processStake(uint256 _amount, address _receiver) internal updateReward(_receiver) {\n        require(_amount > 0, 'RewardPool : Cannot stake 0');\n        \n        //also stake to linked rewards\n        for(uint i=0; i < extraRewards.length; i++){\n            IRewards(extraRewards[i]).stake(_receiver, _amount);\n        }\n\n        _totalSupply = _totalSupply.add(_amount);\n        _balances[_receiver] = _balances[_receiver].add(_amount);\n    }\n\n    function withdraw(uint256 amount, bool claim)\n        public\n        updateReward(msg.sender)\n        returns(bool)\n    {\n        require(amount > 0, 'RewardPool : Cannot withdraw 0');\n\n        //also withdraw from linked rewards\n        for(uint i=0; i < extraRewards.length; i++){\n            IRewards(extraRewards[i]).withdraw(msg.sender, amount);\n        }\n\n        _totalSupply = _totalSupply.sub(amount);\n        _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n        stakingToken.safeTransfer(msg.sender, amount);\n        emit Withdrawn(msg.sender, amount);\n     \n        if(claim){\n            getReward(msg.sender,true);\n        }\n\n        return true;\n    }\n\n    function withdrawAll(bool claim) external{\n        withdraw(_balances[msg.sender],claim);\n    }\n\n    function withdrawAndUnwrap(uint256 amount, bool claim) public returns(bool){\n        _withdrawAndUnwrapTo(amount, msg.sender, msg.sender);\n        //get rewards too\n        if(claim){\n            getReward(msg.sender,true);\n        }\n        return true;\n    }\n\n    function _withdrawAndUnwrapTo(uint256 amount, address from, address receiver) internal updateReward(from) returns(bool){\n        //also withdraw from linked rewards\n        for(uint i=0; i < extraRewards.length; i++){\n            IRewards(extraRewards[i]).withdraw(from, amount);\n        }\n        \n        _totalSupply = _totalSupply.sub(amount);\n        _balances[from] = _balances[from].sub(amount);\n\n        //tell operator to withdraw from here directly to user\n        IDeposit(operator).withdrawTo(pid,amount,receiver);\n        emit Withdrawn(from, amount);\n\n        return true;\n    }\n\n    function withdrawAllAndUnwrap(bool claim) external{\n        withdrawAndUnwrap(_balances[msg.sender],claim);\n    }\n\n    /**\n     * @dev Gives a staker their rewards, with the option of claiming extra rewards\n     * @param _account     Account for which to claim\n     * @param _claimExtras Get the child rewards too?\n     */\n    function getReward(address _account, bool _claimExtras) public updateReward(_account) returns(bool){\n        uint256 reward = earned(_account);\n        if (reward > 0) {\n            rewards[_account] = 0;\n            rewardToken.safeTransfer(_account, reward);\n            IDeposit(operator).rewardClaimed(pid, _account, reward);\n            emit RewardPaid(_account, reward);\n        }\n\n        //also get rewards from linked rewards\n        if(_claimExtras){\n            for(uint i=0; i < extraRewards.length; i++){\n                IRewards(extraRewards[i]).getReward(_account);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @dev Called by a staker to get their allocated rewards\n     */\n    function getReward() external returns(bool){\n        getReward(msg.sender,true);\n        return true;\n    }\n\n    /**\n     * @dev Donate some extra rewards to this contract\n     */\n    function donate(uint256 _amount) external returns(bool){\n        IERC20(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);\n        queuedRewards = queuedRewards.add(_amount);\n    }\n\n    /**\n     * @dev Processes queued rewards in isolation, providing the period has finished.\n     *      This allows a cheaper way to trigger rewards on low value pools.\n     */\n    function processIdleRewards() external {\n        if (block.timestamp >= periodFinish && queuedRewards > 0) {\n            notifyRewardAmount(queuedRewards);\n            queuedRewards = 0;\n        }\n    }\n\n    /**\n     * @dev Called by the booster to allocate new Crv rewards to this pool\n     *      Curve is queued for rewards and the distribution only begins once the new rewards are sufficiently\n     *      large, or the epoch has ended.\n     */\n    function queueNewRewards(uint256 _rewards) external returns(bool){\n        require(msg.sender == operator, \"!authorized\");\n\n        _rewards = _rewards.add(queuedRewards);\n\n        if (block.timestamp >= periodFinish) {\n            notifyRewardAmount(_rewards);\n            queuedRewards = 0;\n            return true;\n        }\n\n        //et = now - (finish-duration)\n        uint256 elapsedTime = block.timestamp.sub(periodFinish.sub(duration));\n        //current at now: rewardRate * elapsedTime\n        uint256 currentAtNow = rewardRate * elapsedTime;\n        uint256 queuedRatio = currentAtNow.mul(1000).div(_rewards);\n\n        //uint256 queuedRatio = currentRewards.mul(1000).div(_rewards);\n        if(queuedRatio < newRewardRatio){\n            notifyRewardAmount(_rewards);\n            queuedRewards = 0;\n        }else{\n            queuedRewards = _rewards;\n        }\n        return true;\n    }\n\n    function notifyRewardAmount(uint256 reward)\n        internal\n        updateReward(address(0))\n    {\n        historicalRewards = historicalRewards.add(reward);\n        if (block.timestamp >= periodFinish) {\n            rewardRate = reward.div(duration);\n        } else {\n            uint256 remaining = periodFinish.sub(block.timestamp);\n            uint256 leftover = remaining.mul(rewardRate);\n            reward = reward.add(leftover);\n            rewardRate = reward.div(duration);\n        }\n        currentRewards = reward;\n        lastUpdateTime = block.timestamp;\n        periodFinish = block.timestamp.add(duration);\n        emit RewardAdded(reward);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/BaseRewardPool4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport { BaseRewardPool, IDeposit } from \"./BaseRewardPool.sol\";\nimport { IERC4626, IERC20Metadata } from \"./interfaces/IERC4626.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts-0.6/utils/ReentrancyGuard.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   BaseRewardPool4626\n * @notice  Simply wraps the BaseRewardPool with the new IERC4626 Vault standard functions.\n * @dev     See https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol#L58\n *          This is not so much a vault as a Reward Pool, therefore asset:share ratio is always 1:1.\n *          To create most utility for this RewardPool, the \"asset\" has been made to be the crvLP token,\n *          as opposed to the cvxLP token. Therefore, users can easily deposit crvLP, and it will first\n *          go to the Booster and mint the cvxLP before performing the normal staking function.\n */\ncontract BaseRewardPool4626 is BaseRewardPool, ReentrancyGuard, IERC4626 {\n    using SafeERC20 for IERC20;\n\n    /**\n     * @notice The address of the underlying ERC20 token used for\n     * the Vault for accounting, depositing, and withdrawing.\n     */\n    address public override asset;\n\n    mapping (address => mapping (address => uint256)) private _allowances;\n\n    /**\n     * @dev See BaseRewardPool.sol\n     */\n    constructor(\n        uint256 pid_,\n        address stakingToken_,\n        address rewardToken_,\n        address operator_,\n        address rewardManager_,\n        address lptoken_\n    ) public BaseRewardPool(pid_, stakingToken_, rewardToken_, operator_, rewardManager_) {\n        asset = lptoken_;\n        IERC20(asset).safeApprove(operator_, type(uint256).max);\n    }\n\n    /**\n     * @notice Total amount of the underlying asset that is \"managed\" by Vault.\n     */\n    function totalAssets() external view virtual override returns(uint256){\n        return totalSupply();\n    }\n\n    /**\n     * @notice Mints `shares` Vault shares to `receiver`.\n     * @dev Because `asset` is not actually what is collected here, first wrap to required token in the booster.\n     */\n    function deposit(uint256 assets, address receiver) public virtual override nonReentrant returns (uint256) {\n        // Transfer \"asset\" (crvLP) from sender\n        IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);\n\n        // Convert crvLP to cvxLP through normal booster deposit process, but don't stake\n        uint256 balBefore = stakingToken.balanceOf(address(this));\n        IDeposit(operator).deposit(pid, assets, false);\n        uint256 balAfter = stakingToken.balanceOf(address(this));\n\n        require(balAfter.sub(balBefore) >= assets, \"!deposit\");\n\n        // Perform stake manually, now that the funds have been received\n        _processStake(assets, receiver);\n\n        emit Deposit(msg.sender, receiver, assets, assets);\n        emit Staked(receiver, assets);\n        return assets;\n    }\n\n    /**\n     * @notice Mints exactly `shares` Vault shares to `receiver`\n     * by depositing `assets` of underlying tokens.\n     */\n    function mint(uint256 shares, address receiver) external virtual override returns (uint256) {\n        return deposit(shares, receiver);\n    }\n\n    /**\n     * @notice Redeems `shares` from `owner` and sends `assets`\n     * of underlying tokens to `receiver`.\n     */\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) public virtual override nonReentrant returns (uint256) {\n        if (msg.sender != owner) {\n            _approve(owner, msg.sender, _allowances[owner][msg.sender].sub(assets, \"ERC4626: withdrawal amount exceeds allowance\"));\n        }\n        \n        _withdrawAndUnwrapTo(assets, owner, receiver);\n\n        emit Withdraw(msg.sender, receiver, owner, assets, assets);\n        return assets;\n    }\n\n    /**\n     * @notice Redeems `shares` from `owner` and sends `assets`\n     * of underlying tokens to `receiver`.\n     */\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) external virtual override returns (uint256) {\n        return withdraw(shares, receiver, owner);\n    }\n\n    /**\n     * @notice The amount of shares that the vault would\n     * exchange for the amount of assets provided, in an\n     * ideal scenario where all the conditions are met.\n     */\n    function convertToShares(uint256 assets) public view virtual override returns (uint256) {\n        return assets;\n    }\n\n    /**\n     * @notice The amount of assets that the vault would\n     * exchange for the amount of shares provided, in an\n     * ideal scenario where all the conditions are met.\n     */\n    function convertToAssets(uint256 shares) public view virtual override returns (uint256) {\n        return shares;\n    }\n\n    /**\n     * @notice Total number of underlying assets that can\n     * be deposited by `owner` into the Vault, where `owner`\n     * corresponds to the input parameter `receiver` of a\n     * `deposit` call.\n     */\n    function maxDeposit(address /* owner */) public view virtual override returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /**\n     * @notice Allows an on-chain or off-chain user to simulate\n     * the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     */    \n    function previewDeposit(uint256 assets) external view virtual override returns(uint256){\n        return convertToShares(assets);\n    }\n\n    /**\n     * @notice Total number of underlying shares that can be minted\n     * for `owner`, where `owner` corresponds to the input\n     * parameter `receiver` of a `mint` call.\n     */\n    function maxMint(address owner) external view virtual override returns (uint256) {\n        return maxDeposit(owner);\n    }\n\n    /**    \n     * @notice Allows an on-chain or off-chain user to simulate\n     * the effects of their mint at the current block, given\n     * current on-chain conditions.\n     */\n    function previewMint(uint256 shares) external view virtual override returns(uint256){\n        return convertToAssets(shares);\n    }\n\n    /**\n     * @notice Total number of underlying assets that can be\n     * withdrawn from the Vault by `owner`, where `owner`\n     * corresponds to the input parameter of a `withdraw` call.\n     */\n    function maxWithdraw(address owner) public view virtual override returns (uint256) {\n        return balanceOf(owner);\n    }\n\n    /**    \n     * @notice Allows an on-chain or off-chain user to simulate\n     * the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     */\n    function previewWithdraw(uint256 assets) public view virtual override returns(uint256 shares){\n        return convertToShares(assets);\n    }\n\n    /**\n     * @notice Total number of underlying shares that can be\n     * redeemed from the Vault by `owner`, where `owner` corresponds\n     * to the input parameter of a `redeem` call.\n     */\n    function maxRedeem(address owner) external view virtual override returns (uint256) {\n        return maxWithdraw(owner);\n    }\n    /**    \n     * @notice Allows an on-chain or off-chain user to simulate\n     * the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     */\n    function previewRedeem(uint256 shares) external view virtual override returns(uint256){\n        return previewWithdraw(shares);\n    }\n\n\n    /* ========== IERC20 ========== */\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view override returns (string memory) {\n        return string(\n            abi.encodePacked(IERC20Metadata(address(stakingToken)).name(), \" Vault\")\n        );\n    }\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view override returns (string memory) {\n        return string(\n            abi.encodePacked(IERC20Metadata(address(stakingToken)).symbol(), \"-vault\")\n        );\n    }\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() public view override(BaseRewardPool, IERC20) returns (uint256) {\n        return BaseRewardPool.totalSupply();\n    }\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) public view override(BaseRewardPool, IERC20) returns (uint256) {\n        return BaseRewardPool.balanceOf(account);\n    }\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address /* recipient */, uint256 /* amount */) external override returns (bool) {\n        revert(\"ERC4626: Not supported\");\n    }\n\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC4626: approve from the zero address\");\n        require(spender != address(0), \"ERC4626: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     */\n    function transferFrom(address /* sender */, address /* recipient */, uint256 /* amount */) external override returns (bool) {\n        revert(\"ERC4626: Not supported\");\n    }\n}"
      },
      "convex-platform/contracts/contracts/interfaces/IERC4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport { IERC20Metadata } from \"./IERC20Metadata.sol\";\n\n/// @title ERC4626 interface\n/// See: https://eips.ethereum.org/EIPS/eip-4626\n\nabstract contract IERC4626 is IERC20Metadata {\n\n    /*////////////////////////////////////////////////////////\n                      Events\n    ////////////////////////////////////////////////////////*/\n\n    /// @notice `caller` has exchanged `assets` for `shares`, and transferred those `shares` to `owner`\n    event Deposit(\n        address indexed caller,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /// @notice `caller` has exchanged `shares`, owned by `owner`, for\n    ///         `assets`, and transferred those `assets` to `receiver`.\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /*////////////////////////////////////////////////////////\n                      Vault properties\n    ////////////////////////////////////////////////////////*/\n\n    /// @notice The address of the underlying ERC20 token used for\n    /// the Vault for accounting, depositing, and withdrawing.\n    function asset() external view virtual returns(address);\n\n    /// @notice Total amount of the underlying asset that\n    /// is \"managed\" by Vault.\n    function totalAssets() external view virtual returns(uint256);\n\n    /*////////////////////////////////////////////////////////\n                      Deposit/Withdrawal Logic\n    ////////////////////////////////////////////////////////*/\n\n    /// @notice Mints `shares` Vault shares to `receiver` by\n    /// depositing exactly `assets` of underlying tokens.\n    function deposit(uint256 assets, address receiver) external virtual returns(uint256 shares);\n\n    /// @notice Mints exactly `shares` Vault shares to `receiver`\n    /// by depositing `assets` of underlying tokens.\n    function mint(uint256 shares, address receiver) external virtual returns(uint256 assets);\n\n    /// @notice Redeems `shares` from `owner` and sends `assets`\n    /// of underlying tokens to `receiver`.\n    function withdraw(uint256 assets, address receiver, address owner) external virtual returns(uint256 shares);\n\n    /// @notice Redeems `shares` from `owner` and sends `assets`\n    /// of underlying tokens to `receiver`.\n    function redeem(uint256 shares, address receiver, address owner) external virtual returns(uint256 assets);\n\n    /*////////////////////////////////////////////////////////\n                      Vault Accounting Logic\n    ////////////////////////////////////////////////////////*/\n\n    /// @notice The amount of shares that the vault would\n    /// exchange for the amount of assets provided, in an\n    /// ideal scenario where all the conditions are met.\n    function convertToShares(uint256 assets) external view virtual returns(uint256 shares);\n\n    /// @notice The amount of assets that the vault would\n    /// exchange for the amount of shares provided, in an\n    /// ideal scenario where all the conditions are met.\n    function convertToAssets(uint256 shares) external view virtual returns(uint256 assets);\n\n    /// @notice Total number of underlying assets that can\n    /// be deposited by `owner` into the Vault, where `owner`\n    /// corresponds to the input parameter `receiver` of a\n    /// `deposit` call.\n    function maxDeposit(address owner) external view virtual returns(uint256 maxAssets);\n\n    /// @notice Allows an on-chain or off-chain user to simulate\n    /// the effects of their deposit at the current block, given\n    /// current on-chain conditions.\n    function previewDeposit(uint256 assets) external view virtual returns(uint256 shares);\n\n    /// @notice Total number of underlying shares that can be minted\n    /// for `owner`, where `owner` corresponds to the input\n    /// parameter `receiver` of a `mint` call.\n    function maxMint(address owner) external view virtual returns(uint256 maxShares);\n\n    /// @notice Allows an on-chain or off-chain user to simulate\n    /// the effects of their mint at the current block, given\n    /// current on-chain conditions.\n    function previewMint(uint256 shares) external view virtual returns(uint256 assets);\n\n    /// @notice Total number of underlying assets that can be\n    /// withdrawn from the Vault by `owner`, where `owner`\n    /// corresponds to the input parameter of a `withdraw` call.\n    function maxWithdraw(address owner) external view virtual returns(uint256 maxAssets);\n\n    /// @notice Allows an on-chain or off-chain user to simulate\n    /// the effects of their withdrawal at the current block,\n    /// given current on-chain conditions.\n    function previewWithdraw(uint256 assets) external view virtual returns(uint256 shares);\n\n    /// @notice Total number of underlying shares that can be\n    /// redeemed from the Vault by `owner`, where `owner` corresponds\n    /// to the input parameter of a `redeem` call.\n    function maxRedeem(address owner) external view virtual returns(uint256 maxShares);\n\n    /// @notice Allows an on-chain or off-chain user to simulate\n    /// the effects of their redeemption at the current block,\n    /// given current on-chain conditions.\n    function previewRedeem(uint256 shares) external view virtual returns(uint256 assets);\n}"
      },
      "@openzeppelin/contracts-0.6/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor () internal {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and make it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        // On the first call to nonReentrant, _notEntered will be true\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/interfaces/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport { IERC20 } from \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n\n"
      },
      "convex-platform/contracts/contracts/RewardFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./BaseRewardPool4626.sol\";\nimport \"./VirtualBalanceRewardPool.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n\n/**\n * @title   RewardFactory\n * @author  ConvexFinance\n * @notice  Used to deploy reward pools when a new pool is added to the Booster\n *          contract. This contract deploys two types of reward pools:\n *          - BaseRewardPool handles CRV rewards for guages\n *          - VirtualBalanceRewardPool for extra rewards\n */\ncontract RewardFactory {\n    using Address for address;\n\n    address public immutable operator;\n    address public immutable crv;\n\n    mapping (address => bool) private rewardAccess;\n    mapping(address => uint256[]) public rewardActiveList;\n\n\n    event RewardPoolCreated(address rewardPool, uint256 _pid, address depositToken);\n    event TokenRewardPoolCreated(address rewardPool, address token, address mainRewards, address operator);\n\n    event AccessChanged(address stash, bool hasAccess);\n\n    /**\n     * @param _operator   Contract operator is Booster\n     * @param _crv        CRV token address\n     */\n    constructor(address _operator, address _crv) public {\n        operator = _operator;\n        crv = _crv;\n    }\n\n    //stash contracts need access to create new Virtual balance pools for extra gauge incentives(ex. snx)\n    function setAccess(address _stash, bool _status) external{\n        require(msg.sender == operator, \"!auth\");\n        rewardAccess[_stash] = _status;\n\n        emit AccessChanged(_stash, _status);\n    }\n\n    /**\n     * @notice Create a Managed Reward Pool to handle distribution of all crv mined in a pool\n     */\n    function CreateCrvRewards(uint256 _pid, address _depositToken, address _lptoken) external returns (address) {\n        require(msg.sender == operator, \"!auth\");\n\n        //operator = booster(deposit) contract so that new crv can be added and distributed\n        //reward manager = this factory so that extra incentive tokens(ex. snx) can be linked to the main managed reward pool\n        BaseRewardPool4626 rewardPool = new BaseRewardPool4626(_pid,_depositToken,crv,operator, address(this), _lptoken);\n\n        emit RewardPoolCreated(address(rewardPool), _pid, _depositToken);\n        return address(rewardPool);\n    }\n\n    /**\n     * @notice  Create a virtual balance reward pool that mimics the balance of a pool's main reward contract\n     *          used for extra incentive tokens(ex. snx) as well as vecrv fees\n     */\n    function CreateTokenRewards(address _token, address _mainRewards, address _operator) external returns (address) {\n        require(msg.sender == operator || rewardAccess[msg.sender] == true, \"!auth\");\n\n        //create new pool, use main pool for balance lookup\n        VirtualBalanceRewardPool rewardPool = new VirtualBalanceRewardPool(_mainRewards,_token,_operator);\n        address rAddress = address(rewardPool);\n        //add the new pool to main pool's list of extra rewards, assuming this factory has \"reward manager\" role\n        IRewards(_mainRewards).addExtraReward(rAddress);\n\n        emit TokenRewardPoolCreated(rAddress, _token, _mainRewards, _operator);\n        //return new pool's address\n        return rAddress;\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/PoolManagerV3.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/IGaugeController.sol\";\n\n/** \n * @title   PoolManagerV3\n * @author  ConvexFinance\n * @notice  Pool Manager v3\n *          PoolManagerV3 calls addPool on PoolManagerShutdownProxy which calls\n *          addPool on PoolManagerProxy which calls addPool on Booster. \n *          PoolManager-ception\n * @dev     Add pools to the Booster contract\n */\ncontract PoolManagerV3{\n\n    address public immutable pools;\n    address public immutable gaugeController;\n    address public operator;\n\n    bool public protectAddPool;\n    \n    /**\n     * @param _pools            Currently PoolManagerSecondaryProxy\n     * @param _gaugeController  Curve gauge controller e.g: (0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB)\n     * @param _operator         Convex multisig\n     */\n    constructor(\n        address _pools, \n        address _gaugeController, \n        address _operator\n    ) public {\n        pools = _pools;\n        gaugeController = _gaugeController;\n        operator = _operator;\n        protectAddPool = true;\n    }\n\n    function setOperator(address _operator) external {\n        require(msg.sender == operator, \"!auth\");\n        operator = _operator;\n    }\n  \n    /**\n     * @notice set if addPool is only callable by operator\n     */\n    function setProtectPool(bool _protectAddPool) external {\n        require(msg.sender == operator, \"!auth\");\n        protectAddPool = _protectAddPool;\n    }\n\n    /**\n     * @notice Add a new curve pool to the system. (default stash to v3)\n     */\n    function addPool(address _gauge) external returns(bool){\n        _addPool(_gauge,3);\n        return true;\n    }\n\n    /**\n     * @notice Add a new curve pool to the system\n     */\n    function addPool(address _gauge, uint256 _stashVersion) external returns(bool){\n        _addPool(_gauge,_stashVersion);\n        return true;\n    }\n\n    function _addPool(address _gauge, uint256 _stashVersion) internal{\n        if(protectAddPool) {\n            require(msg.sender == operator, \"!auth\");\n        }\n        //get lp token from gauge\n        address lptoken = ICurveGauge(_gauge).lp_token();\n\n        //gauge/lptoken address checks will happen in the next call\n        IPools(pools).addPool(lptoken,_gauge,_stashVersion);\n    }\n\n    function forceAddPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool){\n        require(msg.sender==operator, \"!auth\");\n        \n        //force add pool without weight checks (can only be used on new token and gauge addresses)\n        return IPools(pools).forceAddPool(_lptoken, _gauge, _stashVersion);\n    }\n\n    function shutdownPool(uint256 _pid) external returns(bool){\n        require(msg.sender==operator, \"!auth\");\n\n        IPools(pools).shutdownPool(_pid);\n        return true;\n    }\n\n}\n"
      },
      "convex-platform/contracts/contracts/interfaces/IGaugeController.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IGaugeController {\n    function get_gauge_weight(address _gauge) external view returns(uint256);\n    function vote_user_slopes(address,address) external view returns(uint256,uint256,uint256);//slope,power,end\n    function vote_for_gauge_weights(address,uint256) external;\n    function add_gauge(address,int128,uint256) external;\n}"
      },
      "convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/IGaugeController.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\n\n/**\n * @title   PoolManagerSecondaryProxy\n * @author  ConvexFinance\n * @notice  Basically a PoolManager that has a better shutdown and calls addPool on PoolManagerProxy. \n *          Immutable pool manager proxy to enforce that when a  pool is shutdown, the proper number\n *          of lp tokens are returned to the booster contract for withdrawal.\n */\ncontract PoolManagerSecondaryProxy{\n    using SafeMath for uint256;\n\n    address public immutable gaugeController;\n    address public immutable pools;\n    address public immutable booster;\n    address public owner;\n    address public operator;\n    bool public isShutdown;\n\n    mapping(address => bool) public usedMap;\n\n    /**\n     * @param _gaugeController Curve Gauge controller (0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB)\n     * @param _pools PoolManagerProxy (0x5F47010F230cE1568BeA53a06eBAF528D05c5c1B)\n     * @param _booster Booster\n     * @param _owner Executoor\n     */\n    constructor(\n        address _gaugeController,\n        address _pools,\n        address _booster,\n        address _owner\n    ) public {\n        gaugeController = _gaugeController;\n        pools = _pools;\n        booster = _booster;\n        owner = _owner; \n        operator = msg.sender;\n    }\n\n    modifier onlyOwner() {\n        require(owner == msg.sender, \"!owner\");\n        _;\n    }\n\n    modifier onlyOperator() {\n        require(operator == msg.sender, \"!op\");\n        _;\n    }\n\n    //set owner - only OWNER\n    function setOwner(address _owner) external onlyOwner{\n        owner = _owner;\n    }\n\n    //set operator - only OWNER\n    function setOperator(address _operator) external onlyOwner{\n        operator = _operator;\n    }\n\n    //manual set an address to used state\n    function setUsedAddress(address[] memory usedList) external onlyOwner{\n        for(uint i=0; i < usedList.length; i++){\n            usedMap[usedList[i]] = true;\n        }\n    }\n\n    //shutdown pool management and disallow new pools. change is immutable\n    function shutdownSystem() external onlyOwner{\n        isShutdown = true;\n    }\n\n    /**\n     * @notice  Shutdown a pool - only OPERATOR\n     * @dev     Shutdowns a pool and ensures all the LP tokens are properly\n     *          withdrawn to the Booster contract \n     */\n    function shutdownPool(uint256 _pid) external onlyOperator returns(bool){\n        //get pool info\n        (address lptoken, address depositToken,,,,bool isshutdown) = IPools(booster).poolInfo(_pid);\n        require(!isshutdown, \"already shutdown\");\n\n        //shutdown pool and get before and after amounts\n        uint256 beforeBalance = IERC20(lptoken).balanceOf(booster);\n        IPools(pools).shutdownPool(_pid);\n        uint256 afterBalance = IERC20(lptoken).balanceOf(booster);\n\n        //check that proper amount of tokens were withdrawn(will also fail if already shutdown)\n        require( afterBalance.sub(beforeBalance) >= IERC20(depositToken).totalSupply(), \"supply mismatch\");\n\n        return true;\n    }\n\n    //add a new pool if it has weight on the gauge controller - only OPERATOR\n    function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){\n        //check that the pool as weight\n        uint256 weight = IGaugeController(gaugeController).get_gauge_weight(_gauge);\n        require(weight > 0, \"must have weight\");\n\n        return _addPool(_lptoken, _gauge, _stashVersion);\n    }\n\n    //force add a new pool, but only for addresses that have never been used before - only OPERATOR\n    function forceAddPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){\n        require(!usedMap[_lptoken] && !usedMap[_gauge], \"cant force used pool\");\n\n        return _addPool(_lptoken, _gauge, _stashVersion);\n    }\n\n    //internal add pool and updated used list\n    function _addPool(address _lptoken, address _gauge, uint256 _stashVersion) internal returns(bool){\n        require(!isShutdown, \"shutdown\");\n\n        usedMap[_lptoken] = true;\n        usedMap[_gauge] = true;\n\n        return IPools(pools).addPool(_lptoken,_gauge,_stashVersion);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/PoolManagerProxy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\n\n/**\n * @title   PoolManagerProxy\n * @author  ConvexFinance\n * @notice  Immutable pool manager proxy to enforce that there are no multiple pools of the same gauge\n *          as well as new lp tokens are not gauge tokens\n * @dev     Called by PoolManagerShutdownProxy \n */\ncontract PoolManagerProxy{\n\n    address public immutable pools;\n    address public owner;\n    address public operator;\n\n    /**\n     * @param _pools      Contract can call addPool currently Booster\n     * @param _owner      Contract owner currently multisig\n     */\n    constructor(\n      address _pools, \n      address _owner\n    ) public {\n        pools = _pools;\n        owner = _owner;\n        operator = msg.sender;\n    }\n\n    modifier onlyOwner() {\n        require(owner == msg.sender, \"!owner\");\n        _;\n    }\n\n    modifier onlyOperator() {\n        require(operator == msg.sender, \"!op\");\n        _;\n    }\n\n    //set owner - only OWNER\n    function setOwner(address _owner) external onlyOwner{\n        owner = _owner;\n    }\n\n    //set operator - only OWNER\n    function setOperator(address _operator) external onlyOwner{\n        operator = _operator;\n    }\n\n    // sealed to be immutable\n    // function revertControl() external{\n    // }\n\n    //shutdown a pool - only OPERATOR\n    function shutdownPool(uint256 _pid) external onlyOperator returns(bool){\n        return IPools(pools).shutdownPool(_pid);\n    }\n\n    /**\n     * @notice  Add pool to system\n     * @dev     Only callable by the operator looks up the gauge from the gaugeMap in Booster to ensure\n     *          it hasn't already been added\n     */\n    function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){\n\n        require(_gauge != address(0),\"gauge is 0\");\n        require(_lptoken != address(0),\"lp token is 0\");\n\n        //check if a pool with this gauge already exists\n        bool gaugeExists = IPools(pools).gaugeMap(_gauge);\n        require(!gaugeExists, \"already registered gauge\");\n\n        //must also check that the lp token is not a registered gauge\n        //because curve gauges are tokenized\n        gaugeExists = IPools(pools).gaugeMap(_lptoken);\n        require(!gaugeExists, \"already registered lptoken\");\n\n        return IPools(pools).addPool(_lptoken,_gauge,_stashVersion);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/ExtraRewardStashV3.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"./interfaces/IRewardHook.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n\n/**\n * @title   ExtraRewardStashV3\n * @author  ConvexFinance\n * @notice  ExtraRewardStash for pools added to the Booster to handle extra rewards\n *          that aren't CRV that can be claimed from a gauge.\n *          - v3.0: Support for curve gauge reward redirect\n *            The Booster contract has a function called setGaugeRedirect. This function calls set_rewards_receiver\n *            On the Curve Guage. This tells the Gauge where to send rewards. The Booster crafts the calldata for this\n *            transaction and then calls execute on the VoterProxy which executes this transaction on the Curve Gauge\n *          - v3.1: Support for arbitrary token rewards outside of gauge rewards add \n *            reward hook to pull rewards during claims\n *          - v3.2: Move constuctor to init function for proxy creation\n */\ncontract ExtraRewardStashV3 {\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public immutable crv;\n    uint256 private constant maxRewards = 8;\n\n    uint256 public pid;\n    address public operator;\n    address public staker;\n    address public gauge;\n    address public rewardFactory;\n   \n    mapping(address => uint256) public historicalRewards;\n    bool public hasRedirected;\n    bool public hasCurveRewards;\n\n    struct TokenInfo {\n        address token;\n        address rewardAddress;\n    }\n\n    //use mapping+array so that we dont have to loop check each time setToken is called\n    mapping(address => TokenInfo) public tokenInfo;\n    address[] public tokenList;\n\n    //address to call for reward pulls\n    address public rewardHook;\n  \n    /**\n     * @param _crv CRV token address\n     */\n    constructor(address _crv) public {\n      crv = _crv;\n    }\n\n    /**\n     * @param _pid        Pool ID\n     * @param _operator   Operator (Booster)\n     * @param _staker     Staker (VoterProxy)\n     * @param _gauge      Gauge\n     * @param _rFactory   Reward factory\n     */\n    function initialize(uint256 _pid, address _operator, address _staker, address _gauge, address _rFactory) external {\n        require(gauge == address(0),\"!init\");\n        pid = _pid;\n        operator = _operator;\n        staker = _staker;\n        gauge = _gauge;\n        rewardFactory = _rFactory;\n    }\n\n    function getName() external pure returns (string memory) {\n        return \"ExtraRewardStashV3.2\";\n    }\n\n    function tokenCount() external view returns (uint256){\n        return tokenList.length;\n    }\n\n    /**\n     * @notice  Claim rewards from the gauge\n     * @dev     The Stash's claimRewards function calls claimRewards on the Booster contract\n     *          which calls claimRewards on the VoterProxy which calls claim_rewards on the gauge\n     *          If a RewardHook is set onRewardClaim is also called on that\n     *          Called by Booster earmarkRewards\n     *          Guage rewards are sent directly to this stash even though the Curve method claim_rewards\n     *          is being called by the VoterProxy. This is because Curves guages have the ability to redirect\n     *          rewards to somewhere other than msg.sender. This is setup in Booster setGaugeRedirect\n     */\n    function claimRewards() external returns (bool) {\n        require(msg.sender == operator, \"!operator\");\n\n        //this is updateable from v2 gauges now so must check each time.\n        checkForNewRewardTokens();\n\n        //make sure we're redirected\n        if(!hasRedirected){\n            IDeposit(operator).setGaugeRedirect(pid);\n            hasRedirected = true;\n        }\n\n        if(hasCurveRewards){\n            //claim rewards on gauge for staker\n            //using reward_receiver so all rewards will be moved to this stash\n            IDeposit(operator).claimRewards(pid,gauge);\n        }\n\n        //hook for reward pulls\n        if(rewardHook != address(0)){\n            try IRewardHook(rewardHook).onRewardClaim(){\n            }catch{}\n        }\n        return true;\n    }\n   \n\n    //check if gauge rewards have changed\n    function checkForNewRewardTokens() internal {\n        for(uint256 i = 0; i < maxRewards; i++){\n            address token = ICurveGauge(gauge).reward_tokens(i);\n            if (token == address(0)) {\n                break;\n            }\n            if(!hasCurveRewards){\n                hasCurveRewards = true;\n            }\n            setToken(token);\n        }\n    }\n\n    //register an extra reward token to be handled\n    // (any new incentive that is not directly on curve gauges)\n    function setExtraReward(address _token) external{\n        //owner of booster can set extra rewards\n        require(IDeposit(operator).owner() == msg.sender, \"!owner\");\n        require(tokenList.length < 4, \"too many rewards\");\n\n        setToken(_token);\n    }\n\n    function setRewardHook(address _hook) external{\n        //owner of booster can set reward hook\n        require(IDeposit(operator).owner() == msg.sender, \"!owner\");\n        rewardHook = _hook;\n    }\n\n\n    /**\n     * @notice  Add a reward token to the token list so it can be claimed\n     * @dev     For each token that is added as a claimable reward a VirtualRewardsPool\n     *          is deployed to handle virtual distribution of tokens \n     */\n    function setToken(address _token) internal {\n        TokenInfo storage t = tokenInfo[_token];\n\n        if(t.token == address(0)){\n            //set token address\n            t.token = _token;\n\n            //check if crv\n            if(_token != crv){\n                //create new reward contract (for NON-crv tokens only)\n                (,,,address mainRewardContract,,) = IDeposit(operator).poolInfo(pid);\n                address rewardContract = IRewardFactory(rewardFactory).CreateTokenRewards(\n                    _token,\n                    mainRewardContract,\n                    address(this));\n                \n                t.rewardAddress = rewardContract;\n            }\n            //add token to list of known rewards\n            tokenList.push(_token);\n        }\n    }\n\n    //pull assigned tokens from staker to stash\n    function stashRewards() external pure returns(bool){\n\n        //after depositing/withdrawing, extra incentive tokens are claimed\n        //but from v3 this is default to off, and this stash is the reward receiver too.\n\n        return true;\n    }\n\n    /**\n     * @notice  Distribute rewards\n     * @dev     Send all CRV to the Booster contract and send all extra token\n     *          rewards to the rewardContract VirtualRewardsPool\n     *          Called by Booster earmarkRewards\n     */\n    function processStash() external returns(bool){\n        require(msg.sender == operator, \"!operator\");\n\n        uint256 tCount = tokenList.length;\n        for(uint i=0; i < tCount; i++){\n            TokenInfo storage t = tokenInfo[tokenList[i]];\n            address token = t.token;\n            if(token == address(0)) continue;\n            \n            uint256 amount = IERC20(token).balanceOf(address(this));\n            if (amount > 0) {\n                historicalRewards[token] = historicalRewards[token].add(amount);\n                if(token == crv){\n                    //if crv, send back to booster to distribute\n                    IERC20(token).safeTransfer(operator, amount);\n                    continue;\n                }\n            \t//add to reward contract\n            \taddress rewards = t.rewardAddress;\n            \tif(rewards == address(0)) continue;\n            \tIERC20(token).safeTransfer(rewards, amount);\n            \tIRewards(rewards).queueNewRewards(amount);\n            }\n        }\n        return true;\n    }\n\n}\n"
      },
      "convex-platform/contracts/contracts/interfaces/IRewardHook.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IRewardHook {\n    function onRewardClaim() external;\n}"
      },
      "@openzeppelin/contracts-0.6/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\nimport \"../utils/Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor () internal {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/ConvexMasterChef.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts-0.6/utils/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Context.sol\";\nimport \"@openzeppelin/contracts-0.6/access/Ownable.sol\";\nimport \"./interfaces/IRewarder.sol\";\n\n/**\n * @title   ConvexMasterChef\n * @author  ConvexFinance\n * @notice  Masterchef can distribute rewards to n pools over x time\n * @dev     There are some caveats with this usage - once it's turned on it can't be turned off,\n *          and thus it can over complicate the distribution of these rewards.\n *          To kick things off, just transfer CVX here and add some pools - rewards will be distributed\n *          pro-rata based on the allocation points in each pool vs the total alloc.\n */\ncontract ConvexMasterChef is Ownable, ReentrancyGuard {\n    using SafeMath for uint256;\n    using SafeERC20 for IERC20;\n\n    // Info of each user.\n    struct UserInfo {\n        uint256 amount; // How many LP tokens the user has provided.\n        uint256 rewardDebt; // Reward debt. See explanation below.\n        //\n        // We do some fancy math here. Basically, any point in time, the amount of CVXs\n        // entitled to a user but is pending to be distributed is:\n        //\n        //   pending reward = (user.amount * pool.accCvxPerShare) - user.rewardDebt\n        //\n        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n        //   1. The pool's `accCvxPerShare` (and `lastRewardBlock`) gets updated.\n        //   2. User receives the pending reward sent to his/her address.\n        //   3. User's `amount` gets updated.\n        //   4. User's `rewardDebt` gets updated.\n    }\n\n    // Info of each pool.\n    struct PoolInfo {\n        IERC20 lpToken; // Address of LP token contract.\n        uint256 allocPoint; // How many allocation points assigned to this pool. CVX to distribute per block.\n        uint256 lastRewardBlock; // Last block number that CVXs distribution occurs.\n        uint256 accCvxPerShare; // Accumulated CVXs per share, times 1e12. See below.\n        IRewarder rewarder;\n    }\n\n    //cvx\n    IERC20 public immutable cvx;\n    // CVX tokens created per block.\n    uint256 public immutable rewardPerBlock;\n    // Bonus muliplier for early cvx makers.\n    uint256 public constant BONUS_MULTIPLIER = 2;\n\n    // Info of each pool.\n    PoolInfo[] public poolInfo;\n    mapping(address => bool) public isAddedPool;\n    // Info of each user that stakes LP tokens.\n    mapping(uint256 => mapping(address => UserInfo)) public userInfo;\n    // Total allocation points. Must be the sum of all allocation points in all pools.\n    uint256 public totalAllocPoint = 0;\n    // The block number when CVX mining starts.\n    uint256 public immutable startBlock;\n    uint256 public immutable endBlock;\n\n    // Events\n    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);\n    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);\n    event RewardPaid(address indexed user,  uint256 indexed pid, uint256 amount);\n    event EmergencyWithdraw(\n        address indexed user,\n        uint256 indexed pid,\n        uint256 amount\n    );\n\n    constructor(\n        IERC20 _cvx,\n        uint256 _rewardPerBlock,\n        uint256 _startBlock,\n        uint256 _endBlock\n    ) public {\n        cvx = _cvx;\n        isAddedPool[address(_cvx)] = true;\n        rewardPerBlock = _rewardPerBlock;\n        startBlock = _startBlock;\n        endBlock = _endBlock;\n    }\n\n    function poolLength() external view returns (uint256) {\n        return poolInfo.length;\n    }\n\n    // Add a new lp to the pool. Can only be called by the owner.\n    // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.\n    function add(\n        uint256 _allocPoint,\n        IERC20 _lpToken,\n        IRewarder _rewarder\n    ) public onlyOwner nonReentrant {\n        require(poolInfo.length < 32, \"max pools\");\n\n        require(!isAddedPool[address(_lpToken)], \"add: Duplicated LP Token\");\n        isAddedPool[address(_lpToken)] = true;\n\n        massUpdatePools();\n\n        uint256 lastRewardBlock = block.number > startBlock\n            ? block.number\n            : startBlock;\n        totalAllocPoint = totalAllocPoint.add(_allocPoint);\n        poolInfo.push(\n            PoolInfo({\n                lpToken: _lpToken,\n                allocPoint: _allocPoint,\n                lastRewardBlock: lastRewardBlock,\n                accCvxPerShare: 0,\n                rewarder: _rewarder\n            })\n        );\n    }\n\n    // Update the given pool's CVX allocation point. Can only be called by the owner.\n    function set(\n        uint256 _pid,\n        uint256 _allocPoint,\n        IRewarder _rewarder,\n        bool _updateRewarder\n    ) public onlyOwner nonReentrant {\n        massUpdatePools();\n\n        totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(\n            _allocPoint\n        );\n        require(totalAllocPoint > 0, \"!alloc\");\n\n        poolInfo[_pid].allocPoint = _allocPoint;\n        if(_updateRewarder){\n            poolInfo[_pid].rewarder = _rewarder;\n        }\n    }\n\n    // Return reward multiplier over the given _from to _to block.\n    function getMultiplier(uint256 _from, uint256 _to)\n        public\n        view\n        returns (uint256)\n    {\n        uint256 clampedTo = _to > endBlock ? endBlock : _to;\n        uint256 clampedFrom = _from > endBlock ? endBlock : _from;\n        return clampedTo.sub(clampedFrom);\n    }\n\n    // View function to see pending CVXs on frontend.\n    function pendingCvx(uint256 _pid, address _user)\n        external\n        view\n        returns (uint256)\n    {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][_user];\n        uint256 accCvxPerShare = pool.accCvxPerShare;\n        uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n        if (block.number > pool.lastRewardBlock && lpSupply != 0) {\n            uint256 multiplier = getMultiplier(\n                pool.lastRewardBlock,\n                block.number\n            );\n            uint256 cvxReward = multiplier\n                .mul(rewardPerBlock)\n                .mul(pool.allocPoint)\n                .div(totalAllocPoint);\n            accCvxPerShare = accCvxPerShare.add(\n                cvxReward.mul(1e12).div(lpSupply)\n            );\n        }\n        return user.amount.mul(accCvxPerShare).div(1e12).sub(user.rewardDebt);\n    }\n\n    // Update reward vairables for all pools. Be careful of gas spending!\n    function massUpdatePools() public {\n        uint256 length = poolInfo.length;\n        for (uint256 pid = 0; pid < length; ++pid) {\n            updatePool(pid);\n        }\n    }\n\n    // Update reward variables of the given pool to be up-to-date.\n    function updatePool(uint256 _pid) public {\n        PoolInfo storage pool = poolInfo[_pid];\n        if (block.number <= pool.lastRewardBlock) {\n            return;\n        }\n        uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n        if (lpSupply == 0) {\n            pool.lastRewardBlock = block.number;\n            return;\n        }\n        uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);\n        uint256 cvxReward = multiplier\n            .mul(rewardPerBlock)\n            .mul(pool.allocPoint)\n            .div(totalAllocPoint);\n        //cvx.mint(address(this), cvxReward);\n        pool.accCvxPerShare = pool.accCvxPerShare.add(\n            cvxReward.mul(1e12).div(lpSupply)\n        );\n        pool.lastRewardBlock = block.number;\n    }\n\n    // Deposit LP tokens to MasterChef for CVX allocation.\n    function deposit(uint256 _pid, uint256 _amount) public nonReentrant {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        updatePool(_pid);\n        if (user.amount > 0) {\n            uint256 pending = user\n                .amount\n                .mul(pool.accCvxPerShare)\n                .div(1e12)\n                .sub(user.rewardDebt);\n            safeRewardTransfer(msg.sender, pending);\n        }\n        pool.lpToken.safeTransferFrom(\n            address(msg.sender),\n            address(this),\n            _amount\n        );\n        user.amount = user.amount.add(_amount);\n        user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12);\n\n        //extra rewards\n        IRewarder _rewarder = pool.rewarder;\n        if (address(_rewarder) != address(0)) {\n            _rewarder.onReward(_pid, msg.sender, msg.sender, 0, user.amount);\n        }\n\n        emit Deposit(msg.sender, _pid, _amount);\n    }\n\n    // Withdraw LP tokens from MasterChef.\n    function withdraw(uint256 _pid, uint256 _amount) public nonReentrant {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        require(user.amount >= _amount, \"withdraw: not good\");\n        updatePool(_pid);\n        uint256 pending = user.amount.mul(pool.accCvxPerShare).div(1e12).sub(\n            user.rewardDebt\n        );\n        safeRewardTransfer(msg.sender, pending);\n        user.amount = user.amount.sub(_amount);\n        user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12);\n        pool.lpToken.safeTransfer(address(msg.sender), _amount);\n\n        //extra rewards\n        IRewarder _rewarder = pool.rewarder;\n        if (address(_rewarder) != address(0)) {\n            _rewarder.onReward(_pid, msg.sender, msg.sender, pending, user.amount);\n        }\n\n        emit RewardPaid(msg.sender, _pid, pending);\n        emit Withdraw(msg.sender, _pid, _amount);\n    }\n\n    function claim(uint256 _pid, address _account) external nonReentrant {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][_account];\n\n        updatePool(_pid);\n        uint256 pending = user.amount.mul(pool.accCvxPerShare).div(1e12).sub(\n            user.rewardDebt\n        );\n        safeRewardTransfer(_account, pending);\n        user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12);\n\n        //extra rewards\n        IRewarder _rewarder = pool.rewarder;\n        if (address(_rewarder) != address(0)) {\n            _rewarder.onReward(_pid, _account, _account, pending, user.amount);\n        }\n\n        emit RewardPaid(_account, _pid, pending);\n    }\n\n    // Withdraw without caring about rewards. EMERGENCY ONLY.\n    function emergencyWithdraw(uint256 _pid) public nonReentrant {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        pool.lpToken.safeTransfer(address(msg.sender), user.amount);\n        emit EmergencyWithdraw(msg.sender, _pid, user.amount);\n        user.amount = 0;\n        user.rewardDebt = 0;\n\n        //extra rewards\n        IRewarder _rewarder = pool.rewarder;\n        if (address(_rewarder) != address(0)) {\n            _rewarder.onReward(_pid, msg.sender, msg.sender, 0, 0);\n        }\n    }\n\n    // Safe cvx transfer function, just in case if rounding error causes pool to not have enough CVXs.\n    function safeRewardTransfer(address _to, uint256 _amount) internal {\n        uint256 cvxBal = cvx.balanceOf(address(this));\n        if (_amount > cvxBal) {\n            cvx.safeTransfer(_to, cvxBal);\n        } else {\n            cvx.safeTransfer(_to, _amount);\n        }\n    }\n\n}"
      },
      "convex-platform/contracts/contracts/interfaces/IRewarder.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\ninterface IRewarder {\n    using SafeERC20 for IERC20;\n    function onReward(uint256 pid, address user, address recipient, uint256 sushiAmount, uint256 newLpAmount) external;\n    function pendingTokens(uint256 pid, address user, uint256 sushiAmount) external view returns (IERC20[] memory, uint256[] memory);\n}"
      },
      "convex-platform/contracts/contracts/cCrv.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/ERC20.sol\";\n\n\n/**\n * @title   cvxCrvToken\n * @author  ConvexFinance\n * @notice  Dumb ERC20 token that allows the operator (crvDepositor) to mint and burn tokens\n */\ncontract cvxCrvToken is ERC20 {\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public operator;\n\n    constructor(string memory _nameArg, string memory _symbolArg)\n        public\n        ERC20(\n            _nameArg,\n            _symbolArg\n        )\n    {\n        operator = msg.sender;\n    }\n\n    /**\n     * @notice Allows the initial operator (deployer) to set the operator.\n     *         Note - crvDepositor has no way to change this back, so it's effectively immutable\n     */\n    function setOperator(address _operator) external {\n        require(msg.sender == operator, \"!auth\");\n        operator = _operator;\n    }\n\n    /**\n     * @notice Allows the crvDepositor to mint\n     */\n    function mint(address _to, uint256 _amount) external {\n        require(msg.sender == operator, \"!authorized\");\n        \n        _mint(_to, _amount);\n    }\n\n    /**\n     * @notice Allows the crvDepositor to burn\n     */\n    function burn(address _from, uint256 _amount) external {\n        require(msg.sender == operator, \"!authorized\");\n        \n        _burn(_from, _amount);\n    }\n\n}\n"
      },
      "convex-platform/contracts/contracts/CrvDepositor.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n\n/**\n * @title   CrvDepositor\n * @author  ConvexFinance\n * @notice  This is the entry point for CRV > cvxCRV wrapping. It accepts CRV, sends to 'staker'\n *          for depositing into Curves VotingEscrow, and then mints cvxCRV at 1:1 via the 'minter' (cCrv) minus\n *          the lockIncentive (initially 1%) which is used to basically compensate users who call the `lock` function on Curves\n *          system (larger depositors would likely want to lock).\n */\ncontract CrvDepositor{\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public immutable crvBpt;\n    address public immutable escrow;\n    uint256 private constant MAXTIME = 1 * 364 * 86400;\n    uint256 private constant WEEK = 7 * 86400;\n\n    uint256 public lockIncentive = 10; //incentive to users who spend gas to lock crvBpt\n    uint256 public constant FEE_DENOMINATOR = 10000;\n\n    address public feeManager;\n    address public daoOperator;\n    address public immutable staker;\n    address public immutable minter;\n    uint256 public incentiveCrv = 0;\n    uint256 public unlockTime;\n\n    bool public cooldown;\n\n    /**\n     * @param _staker   CVX VoterProxy (0x989AEb4d175e16225E39E87d0D97A3360524AD80)\n     * @param _minter   cvxCRV token (0x62B9c7356A2Dc64a1969e19C23e4f579F9810Aa7)\n     * @param _crvBpt   crvBPT for veCRV deposits\n     * @param _escrow   CRV VotingEscrow (0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2)\n     */\n    constructor(\n        address _staker,\n        address _minter,\n        address _crvBpt,\n        address _escrow,\n        address _daoOperator\n    ) public {\n        staker = _staker;\n        minter = _minter;\n        crvBpt = _crvBpt;\n        escrow = _escrow;\n        feeManager = msg.sender;\n        daoOperator = _daoOperator;\n    }\n\n    function setFeeManager(address _feeManager) external {\n        require(msg.sender == feeManager, \"!auth\");\n        feeManager = _feeManager;\n    }\n\n    function setDaoOperator(address _daoOperator) external {\n        require(msg.sender == daoOperator, \"!auth\");\n        daoOperator = _daoOperator;\n    }\n\n    function setFees(uint256 _lockIncentive) external{\n        require(msg.sender==feeManager, \"!auth\");\n\n        if(_lockIncentive >= 0 && _lockIncentive <= 30){\n            lockIncentive = _lockIncentive;\n       }\n    }\n\n    function setCooldown(bool _cooldown) external {\n      require(msg.sender == daoOperator, \"!auth\");\n      cooldown = _cooldown;\n    }\n\n    /**\n     * @notice Called once to deposit the balance of CRV in this contract to the VotingEscrow\n     */\n    function initialLock() external{\n        require(!cooldown, \"cooldown\");\n        require(msg.sender==feeManager, \"!auth\");\n\n        uint256 vecrv = IERC20(escrow).balanceOf(staker);\n        if(vecrv == 0){\n            uint256 unlockAt = block.timestamp + MAXTIME;\n            uint256 unlockInWeeks = (unlockAt/WEEK)*WEEK;\n\n            //release old lock if exists\n            IStaker(staker).release();\n            //create new lock\n            uint256 crvBalanceStaker = IERC20(crvBpt).balanceOf(staker);\n            IStaker(staker).createLock(crvBalanceStaker, unlockAt);\n            unlockTime = unlockInWeeks;\n        }\n    }\n\n    //lock curve\n    function _lockCurve() internal {\n        if(cooldown) {\n            return;\n        }\n\n        uint256 crvBalance = IERC20(crvBpt).balanceOf(address(this));\n        if(crvBalance > 0){\n            IERC20(crvBpt).safeTransfer(staker, crvBalance);\n        }\n        \n        //increase ammount\n        uint256 crvBalanceStaker = IERC20(crvBpt).balanceOf(staker);\n        if(crvBalanceStaker == 0){\n            return;\n        }\n        \n        //increase amount\n        IStaker(staker).increaseAmount(crvBalanceStaker);\n        \n\n        uint256 unlockAt = block.timestamp + MAXTIME;\n        uint256 unlockInWeeks = (unlockAt/WEEK)*WEEK;\n\n        //increase time too if over 1 week buffer\n        if(unlockInWeeks.sub(unlockTime) >= WEEK){\n            IStaker(staker).increaseTime(unlockAt);\n            unlockTime = unlockInWeeks;\n        }\n    }\n\n    /**\n     * @notice Locks the balance of CRV, and gives out an incentive to the caller\n     */\n    function lockCurve() external {\n        require(!cooldown, \"cooldown\");\n        _lockCurve();\n\n        //mint incentives\n        if(incentiveCrv > 0){\n            ITokenMinter(minter).mint(msg.sender,incentiveCrv);\n            incentiveCrv = 0;\n        }\n    }\n\n    /**\n     * @notice Deposit crvBpt for cvxCrv on behalf of another user\n     * @dev    See depositFor(address, uint256, bool, address) \n     */\n    function deposit(uint256 _amount, bool _lock, address _stakeAddress) public {\n        depositFor(msg.sender, _amount, _lock, _stakeAddress);\n    }\n\n    /**\n     * @notice Deposit crvBpt for cvxCrv\n     * @dev    Can lock immediately or defer locking to someone else by paying a fee.\n     *         while users can choose to lock or defer, this is mostly in place so that\n     *         the cvx reward contract isnt costly to claim rewards.\n     * @param _amount        Units of CRV to deposit\n     * @param _lock          Lock now? or pay ~1% to the locker\n     * @param _stakeAddress  Stake in cvxCrv staking?\n     */\n    function depositFor(address to, uint256 _amount, bool _lock, address _stakeAddress) public {\n        require(_amount > 0,\"!>0\");\n        require(!cooldown, \"cooldown\");\n\n        if(_lock){\n            //lock immediately, transfer directly to staker to skip an erc20 transfer\n            IERC20(crvBpt).safeTransferFrom(msg.sender, staker, _amount);\n            _lockCurve();\n            if(incentiveCrv > 0){\n                //add the incentive tokens here so they can be staked together\n                _amount = _amount.add(incentiveCrv);\n                incentiveCrv = 0;\n            }\n        }else{\n            //move tokens here\n            IERC20(crvBpt).safeTransferFrom(msg.sender, address(this), _amount);\n            //defer lock cost to another user\n            uint256 callIncentive = _amount.mul(lockIncentive).div(FEE_DENOMINATOR);\n            _amount = _amount.sub(callIncentive);\n\n            //add to a pool for lock caller\n            incentiveCrv = incentiveCrv.add(callIncentive);\n        }\n\n        bool depositOnly = _stakeAddress == address(0);\n        if(depositOnly){\n            //mint for to\n            ITokenMinter(minter).mint(to,_amount);\n        }else{\n            //mint here \n            ITokenMinter(minter).mint(address(this),_amount);\n            //stake for to\n            IERC20(minter).safeApprove(_stakeAddress,0);\n            IERC20(minter).safeApprove(_stakeAddress,_amount);\n            IRewards(_stakeAddress).stakeFor(to,_amount);\n        }\n    }\n\n    function deposit(uint256 _amount, bool _lock) external {\n        deposit(_amount,_lock,address(0));\n    }\n\n    function depositAll(bool _lock, address _stakeAddress) external{\n        uint256 crvBal = IERC20(crvBpt).balanceOf(msg.sender);\n        deposit(crvBal,_lock,_stakeAddress);\n    }\n}\n"
      },
      "convex-platform/contracts/contracts/Booster.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.6.12;\n\nimport \"./Interfaces.sol\";\nimport \"@openzeppelin/contracts-0.6/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-0.6/utils/Address.sol\";\nimport \"@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol\";\n\n/**\n * @title   Booster\n * @author  ConvexFinance\n * @notice  Main deposit contract; keeps track of pool info & user deposits; distributes rewards.\n * @dev     They say all paths lead to Rome, and the cvxBooster is no different. This is where it all goes down.\n *          It is responsible for tracking all the pools, it collects rewards from all pools and redirects it.\n */\ncontract Booster{\n    using SafeERC20 for IERC20;\n    using Address for address;\n    using SafeMath for uint256;\n\n    address public immutable crv;\n    address public immutable voteOwnership;\n    address public immutable voteParameter;\n\n    uint256 public lockIncentive = 825; //incentive to crv stakers\n    uint256 public stakerIncentive = 825; //incentive to native token stakers\n    uint256 public earmarkIncentive = 50; //incentive to users who spend gas to make calls\n    uint256 public platformFee = 0; //possible fee to build treasury\n    uint256 public constant MaxFees = 2500;\n    uint256 public constant FEE_DENOMINATOR = 10000;\n\n    address public owner;\n    address public feeManager;\n    address public poolManager;\n    address public immutable staker;\n    address public immutable minter;\n    address public rewardFactory;\n    address public stashFactory;\n    address public tokenFactory;\n    address public rewardArbitrator;\n    address public voteDelegate;\n    address public treasury;\n    address public stakerRewards; //cvx rewards\n    address public lockRewards; //cvxCrv rewards(crv)\n\n    mapping(address => FeeDistro) public feeTokens;\n    struct FeeDistro {\n        address distro;\n        address rewards;\n        bool active;\n    }\n\n    bool public isShutdown;\n\n    struct PoolInfo {\n        address lptoken;\n        address token;\n        address gauge;\n        address crvRewards;\n        address stash;\n        bool shutdown;\n    }\n\n    //index(pid) -> pool\n    PoolInfo[] public poolInfo;\n    mapping(address => bool) public gaugeMap;\n\n    event Deposited(address indexed user, uint256 indexed poolid, uint256 amount);\n    event Withdrawn(address indexed user, uint256 indexed poolid, uint256 amount);\n\n    event PoolAdded(address lpToken, address gauge, address token, address rewardPool, address stash, uint256 pid);\n    event PoolShutdown(uint256 poolId);\n\n    event OwnerUpdated(address newOwner);\n    event FeeManagerUpdated(address newFeeManager);\n    event PoolManagerUpdated(address newPoolManager);\n    event FactoriesUpdated(address rewardFactory, address stashFactory, address tokenFactory);\n    event ArbitratorUpdated(address newArbitrator);\n    event VoteDelegateUpdated(address newVoteDelegate);\n    event RewardContractsUpdated(address lockRewards, address stakerRewards);\n    event FeesUpdated(uint256 lockIncentive, uint256 stakerIncentive, uint256 earmarkIncentive, uint256 platformFee);\n    event TreasuryUpdated(address newTreasury);\n    event FeeInfoUpdated(address feeDistro, address lockFees, address feeToken);\n    event FeeInfoChanged(address feeDistro, bool active);\n\n    /**\n     * @dev Constructor doing what constructors do. It is noteworthy that\n     *      a lot of basic config is set to 0 - expecting subsequent calls to setFeeInfo etc.\n     * @param _staker                 VoterProxy (locks the crv and adds to all gauges)\n     * @param _minter                 CVX token, or the thing that mints it\n     * @param _crv                    CRV\n     * @param _voteOwnership          Address of the Curve DAO responsible for ownership stuff\n     * @param _voteParameter          Address of the Curve DAO responsible for param updates\n     */\n    constructor(\n        address _staker,\n        address _minter,\n        address _crv,\n        address _voteOwnership,\n        address _voteParameter\n    ) public {\n        staker = _staker;\n        minter = _minter;\n        crv = _crv;\n        voteOwnership = _voteOwnership;\n        voteParameter = _voteParameter;\n        isShutdown = false;\n\n        owner = msg.sender;\n        voteDelegate = msg.sender;\n        feeManager = msg.sender;\n        poolManager = msg.sender;\n        treasury = address(0);\n\n        emit OwnerUpdated(msg.sender);\n        emit VoteDelegateUpdated(msg.sender);\n        emit FeeManagerUpdated(msg.sender);\n        emit PoolManagerUpdated(msg.sender);\n    }\n\n\n    /// SETTER SECTION ///\n\n    /**\n     * @notice Owner is responsible for setting initial config, updating vote delegate and shutting system\n     */\n    function setOwner(address _owner) external {\n        require(msg.sender == owner, \"!auth\");\n        owner = _owner;\n\n        emit OwnerUpdated(_owner);\n    }\n\n    /**\n     * @notice Fee Manager can update the fees (lockIncentive, stakeIncentive, earmarkIncentive, platformFee)\n     */\n    function setFeeManager(address _feeM) external {\n        require(msg.sender == owner, \"!auth\");\n        feeManager = _feeM;\n\n        emit FeeManagerUpdated(_feeM);\n    }\n\n    /**\n     * @notice Pool manager is responsible for adding new pools\n     */\n    function setPoolManager(address _poolM) external {\n        require(msg.sender == poolManager, \"!auth\");\n        poolManager = _poolM;\n\n        emit PoolManagerUpdated(_poolM);\n    }\n\n    /**\n     * @notice Factories are used when deploying new pools. Only the stash factory is mutable after init\n     */\n    function setFactories(address _rfactory, address _sfactory, address _tfactory) external {\n        require(msg.sender == owner, \"!auth\");\n\n        //stash factory should be considered more safe to change\n        //updating may be required to handle new types of gauges\n        stashFactory = _sfactory;\n\n        //reward factory only allow this to be called once even if owner\n        //removes ability to inject malicious staking contracts\n        //token factory can also be immutable\n        if(rewardFactory == address(0)){\n            rewardFactory = _rfactory;\n            tokenFactory = _tfactory;\n\n            emit FactoriesUpdated(_rfactory, _sfactory, _tfactory);\n        } else {\n            emit FactoriesUpdated(address(0), _sfactory, address(0));\n        }\n    }\n\n    /**\n     * @notice Arbitrator handles tokens that are used as secondary rewards across multiple pools\n     */\n    function setArbitrator(address _arb) external {\n        require(msg.sender==owner, \"!auth\");\n        rewardArbitrator = _arb;\n\n        emit ArbitratorUpdated(_arb);\n    }\n\n    /**\n     * @notice Vote Delegate has the rights to cast votes on the VoterProxy via the Booster\n     */\n    function setVoteDelegate(address _voteDelegate) external {\n        require(msg.sender==owner, \"!auth\");\n        voteDelegate = _voteDelegate;\n\n        emit VoteDelegateUpdated(_voteDelegate);\n    }\n\n    /**\n     * @notice Only called once, to set the addresses of cvxCrv (lockRewards) and cvx staking (stakerRewards)\n     */\n    function setRewardContracts(address _rewards, address _stakerRewards) external {\n        require(msg.sender == owner, \"!auth\");\n        \n        //reward contracts are immutable or else the owner\n        //has a means to redeploy and mint cvx via rewardClaimed()\n        if(lockRewards == address(0)){\n            lockRewards = _rewards;\n            stakerRewards = _stakerRewards;\n            emit RewardContractsUpdated(_rewards, _stakerRewards);\n        }\n    }\n\n    /**\n     * @notice Set reward token and claim contract\n     * @dev    This creates a secondary (VirtualRewardsPool) rewards contract for the vcxCrv staking contract\n     */\n    function setFeeInfo(address _feeToken, address _feeDistro) external {\n        require(msg.sender == owner, \"!auth\");\n        require(!isShutdown, \"shutdown\");\n        require(lockRewards != address(0) && rewardFactory != address(0), \"!initialised\");\n\n        require(_feeToken != address(0) && _feeDistro != address(0), \"!addresses\");\n        require(IFeeDistributor(_feeDistro).getTokenTimeCursor(_feeToken) > 0, \"!distro\");\n\n        if(feeTokens[_feeToken].distro == address(0)){\n            require(!gaugeMap[_feeToken], \"!token\");\n\n            // Distributed directly\n            if(_feeToken == crv){\n                feeTokens[crv] = FeeDistro({\n                    distro: _feeDistro,\n                    rewards: lockRewards,\n                    active: true\n                });\n                emit FeeInfoUpdated(_feeDistro, lockRewards, crv);\n            } else {\n                //create a new reward contract for the new token\n                require(IRewards(lockRewards).extraRewardsLength() < 10, \"too many rewards\");\n                address rewards = IRewardFactory(rewardFactory).CreateTokenRewards(_feeToken, lockRewards, address(this));\n                feeTokens[_feeToken] = FeeDistro({\n                    distro: _feeDistro,\n                    rewards: rewards,\n                    active: true\n                });\n                emit FeeInfoUpdated(_feeDistro, rewards, _feeToken);\n            }\n        } else {\n            feeTokens[_feeToken].distro = _feeDistro;\n            emit FeeInfoUpdated(_feeDistro, address(0), _feeToken);\n        }\n    }\n\n    /**\n     * @notice Allows turning off or on for fee distro\n     */\n    function updateFeeInfo(address _feeToken, bool _active) external {\n        require(msg.sender==owner, \"!auth\");\n\n        require(feeTokens[_feeToken].distro != address(0), \"Fee doesn't exist\");\n\n        feeTokens[_feeToken].active = _active;\n\n        emit FeeInfoChanged(_feeToken, _active);\n    }\n\n    /**\n     * @notice Fee manager can set all the relevant fees\n     * @param _lockFees     % for cvxCrv stakers where 1% == 100\n     * @param _stakerFees   % for CVX stakers where 1% == 100\n     * @param _callerFees   % for whoever calls the claim where 1% == 100\n     * @param _platform     % for \"treasury\" or vlCVX where 1% == 100\n     */\n    function setFees(uint256 _lockFees, uint256 _stakerFees, uint256 _callerFees, uint256 _platform) external{\n        require(msg.sender==feeManager, \"!auth\");\n\n        uint256 total = _lockFees.add(_stakerFees).add(_callerFees).add(_platform);\n        require(total <= MaxFees, \">MaxFees\");\n\n        require(_lockFees >= 300 && _lockFees <= 1500, \"!lockFees\");\n        require(_stakerFees >= 300 && _stakerFees <= 1500, \"!stakerFees\");\n        require(_callerFees >= 10 && _callerFees <= 100, \"!callerFees\");\n        require(_platform <= 200, \"!platform\");\n\n        lockIncentive = _lockFees;\n        stakerIncentive = _stakerFees;\n        earmarkIncentive = _callerFees;\n        platformFee = _platform;\n\n        emit FeesUpdated(_lockFees, _stakerFees, _callerFees, _platform);\n    }\n\n    /**\n     * @notice Set the address of the treasury (i.e. vlCVX)\n     */\n    function setTreasury(address _treasury) external {\n        require(msg.sender==feeManager, \"!auth\");\n        treasury = _treasury;\n\n        emit TreasuryUpdated(_treasury);\n    }\n\n    /// END SETTER SECTION ///\n\n\n    function poolLength() external view returns (uint256) {\n        return poolInfo.length;\n    }\n\n    /**\n     * @notice Called by the PoolManager (i.e. PoolManagerProxy) to add a new pool - creates all the required\n     *         contracts (DepositToken, RewardPool, Stash) and then adds to the list!\n     */\n    function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool){\n        require(msg.sender==poolManager && !isShutdown, \"!add\");\n        require(_gauge != address(0) && _lptoken != address(0),\"!param\");\n        require(feeTokens[_gauge].distro == address(0), \"!gauge\");\n\n        //the next pool's pid\n        uint256 pid = poolInfo.length;\n\n        //create a tokenized deposit\n        address token = ITokenFactory(tokenFactory).CreateDepositToken(_lptoken);\n        //create a reward contract for crv rewards\n        address newRewardPool = IRewardFactory(rewardFactory).CreateCrvRewards(pid,token,_lptoken);\n        //create a stash to handle extra incentives\n        address stash = IStashFactory(stashFactory).CreateStash(pid,_gauge,staker,_stashVersion);\n\n        //add the new pool\n        poolInfo.push(\n            PoolInfo({\n                lptoken: _lptoken,\n                token: token,\n                gauge: _gauge,\n                crvRewards: newRewardPool,\n                stash: stash,\n                shutdown: false\n            })\n        );\n        gaugeMap[_gauge] = true;\n        //give stashes access to rewardfactory and voteproxy\n        //   voteproxy so it can grab the incentive tokens off the contract after claiming rewards\n        //   reward factory so that stashes can make new extra reward contracts if a new incentive is added to the gauge\n        if(stash != address(0)){\n            poolInfo[pid].stash = stash;\n            IStaker(staker).setStashAccess(stash,true);\n            IRewardFactory(rewardFactory).setAccess(stash,true);\n        }\n\n        emit PoolAdded(_lptoken, _gauge, token, newRewardPool, stash, pid);\n        return true;\n    }\n\n    /**\n     * @notice Shuts down the pool by withdrawing everything from the gauge to here (can later be\n     *         claimed from depositors by using the withdraw fn) and marking it as shut down\n     */\n    function shutdownPool(uint256 _pid) external returns(bool){\n        require(msg.sender==poolManager, \"!auth\");\n        PoolInfo storage pool = poolInfo[_pid];\n\n        //withdraw from gauge\n        try IStaker(staker).withdrawAll(pool.lptoken,pool.gauge){\n        }catch{}\n\n        pool.shutdown = true;\n        gaugeMap[pool.gauge] = false;\n\n        emit PoolShutdown(_pid);\n        return true;\n    }\n\n    /**\n     * @notice Shuts down the WHOLE SYSTEM by withdrawing all the LP tokens to here and then allowing\n     *         for subsequent withdrawal by any depositors.\n     */\n    function shutdownSystem() external{\n        require(msg.sender == owner, \"!auth\");\n        isShutdown = true;\n\n        for(uint i=0; i < poolInfo.length; i++){\n            PoolInfo storage pool = poolInfo[i];\n            if (pool.shutdown) continue;\n\n            address token = pool.lptoken;\n            address gauge = pool.gauge;\n\n            //withdraw from gauge\n            try IStaker(staker).withdrawAll(token,gauge){\n                pool.shutdown = true;\n            }catch{}\n        }\n    }\n\n    /**\n     * @notice  Deposits an \"_amount\" to a given gauge (specified by _pid), mints a `DepositToken`\n     *          and subsequently stakes that on Convex BaseRewardPool\n     */\n    function deposit(uint256 _pid, uint256 _amount, bool _stake) public returns(bool){\n        require(!isShutdown,\"shutdown\");\n        PoolInfo storage pool = poolInfo[_pid];\n        require(pool.shutdown == false, \"pool is closed\");\n\n        //send to proxy to stake\n        address lptoken = pool.lptoken;\n        IERC20(lptoken).safeTransferFrom(msg.sender, staker, _amount);\n\n        //stake\n        address gauge = pool.gauge;\n        require(gauge != address(0),\"!gauge setting\");\n        IStaker(staker).deposit(lptoken,gauge);\n\n        //some gauges claim rewards when depositing, stash them in a seperate contract until next claim\n        address stash = pool.stash;\n        if(stash != address(0)){\n            IStash(stash).stashRewards();\n        }\n\n        address token = pool.token;\n        if(_stake){\n            //mint here and send to rewards on user behalf\n            ITokenMinter(token).mint(address(this),_amount);\n            address rewardContract = pool.crvRewards;\n            IERC20(token).safeApprove(rewardContract,0);\n            IERC20(token).safeApprove(rewardContract,_amount);\n            IRewards(rewardContract).stakeFor(msg.sender,_amount);\n        }else{\n            //add user balance directly\n            ITokenMinter(token).mint(msg.sender,_amount);\n        }\n\n        \n        emit Deposited(msg.sender, _pid, _amount);\n        return true;\n    }\n\n    /**\n     * @notice  Deposits all a senders balance to a given gauge (specified by _pid), mints a `DepositToken`\n     *          and subsequently stakes that on Convex BaseRewardPool\n     */\n    function depositAll(uint256 _pid, bool _stake) external returns(bool){\n        address lptoken = poolInfo[_pid].lptoken;\n        uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n        deposit(_pid,balance,_stake);\n        return true;\n    }\n\n    /**\n     * @notice  Withdraws LP tokens from a given PID (& user).\n     *          1. Burn the cvxLP balance from \"_from\" (implicit balance check)\n     *          2. If pool !shutdown.. withdraw from gauge\n     *          3. If stash, stash rewards\n     *          4. Transfer out the LP tokens\n     */\n    function _withdraw(uint256 _pid, uint256 _amount, address _from, address _to) internal {\n        PoolInfo storage pool = poolInfo[_pid];\n        address lptoken = pool.lptoken;\n        address gauge = pool.gauge;\n\n        //remove lp balance\n        address token = pool.token;\n        ITokenMinter(token).burn(_from,_amount);\n\n        //pull from gauge if not shutdown\n        // if shutdown tokens will be in this contract\n        if (!pool.shutdown) {\n            IStaker(staker).withdraw(lptoken,gauge, _amount);\n        }\n\n        //some gauges claim rewards when withdrawing, stash them in a seperate contract until next claim\n        //do not call if shutdown since stashes wont have access\n        address stash = pool.stash;\n        if(stash != address(0) && !isShutdown && !pool.shutdown){\n            IStash(stash).stashRewards();\n        }\n        \n        //return lp tokens\n        IERC20(lptoken).safeTransfer(_to, _amount);\n\n        emit Withdrawn(_to, _pid, _amount);\n    }\n\n    /**\n     * @notice  Withdraw a given amount from a pool (must already been unstaked from the Convex Reward Pool -\n     *          BaseRewardPool uses withdrawAndUnwrap to get around this)\n     */\n    function withdraw(uint256 _pid, uint256 _amount) public returns(bool){\n        _withdraw(_pid,_amount,msg.sender,msg.sender);\n        return true;\n    }\n\n    /**\n     * @notice  Withdraw all the senders LP tokens from a given gauge\n     */\n    function withdrawAll(uint256 _pid) public returns(bool){\n        address token = poolInfo[_pid].token;\n        uint256 userBal = IERC20(token).balanceOf(msg.sender);\n        withdraw(_pid, userBal);\n        return true;\n    }\n\n    /**\n     * @notice Allows the actual BaseRewardPool to withdraw and send directly to the user\n     */\n    function withdrawTo(uint256 _pid, uint256 _amount, address _to) external returns(bool){\n        address rewardContract = poolInfo[_pid].crvRewards;\n        require(msg.sender == rewardContract,\"!auth\");\n\n        _withdraw(_pid,_amount,msg.sender,_to);\n        return true;\n    }\n\n    /**\n     * @notice set valid vote hash on VoterProxy \n     */\n    function setVote(bytes32 _hash, bool valid) external returns(bool){\n        require(msg.sender == voteDelegate, \"!auth\");\n        \n        IStaker(staker).setVote(_hash, valid);\n        return true;\n    }\n\n    /**\n     * @notice Delegate address votes on dao via VoterProxy\n     */\n    function vote(uint256 _voteId, address _votingAddress, bool _support) external returns(bool){\n        require(msg.sender == voteDelegate, \"!auth\");\n        require(_votingAddress == voteOwnership || _votingAddress == voteParameter, \"!voteAddr\");\n        \n        IStaker(staker).vote(_voteId,_votingAddress,_support);\n        return true;\n    }\n\n    /**\n     * @notice Delegate address votes on gauge weight via VoterProxy\n     */\n    function voteGaugeWeight(address[] calldata _gauge, uint256[] calldata _weight ) external returns(bool){\n        require(msg.sender == voteDelegate, \"!auth\");\n\n        for(uint256 i = 0; i < _gauge.length; i++){\n            IStaker(staker).voteGaugeWeight(_gauge[i],_weight[i]);\n        }\n        return true;\n    }\n\n    /**\n     * @notice Allows a stash to claim secondary rewards from a gauge\n     */\n    function claimRewards(uint256 _pid, address _gauge) external returns(bool){\n        address stash = poolInfo[_pid].stash;\n        require(msg.sender == stash,\"!auth\");\n\n        IStaker(staker).claimRewards(_gauge);\n        return true;\n    }\n\n    /**\n     * @notice Tells the Curve gauge to redirect any accrued rewards to the given stash via the VoterProxy\n     */\n    function setGaugeRedirect(uint256 _pid) external returns(bool){\n        address stash = poolInfo[_pid].stash;\n        require(msg.sender == stash,\"!auth\");\n        address gauge = poolInfo[_pid].gauge;\n        bytes memory data = abi.encodeWithSelector(bytes4(keccak256(\"set_rewards_receiver(address)\")), stash);\n        IStaker(staker).execute(gauge,uint256(0),data);\n        return true;\n    }\n\n    /**\n     * @notice Basically a hugely pivotal function.\n     *         Responsible for collecting the crv from gauge, and then redistributing to the correct place.\n     *         Pays the caller a fee to process this.\n     */\n    function _earmarkRewards(uint256 _pid) internal {\n        PoolInfo storage pool = poolInfo[_pid];\n        require(pool.shutdown == false, \"pool is closed\");\n\n        address gauge = pool.gauge;\n\n        //claim crv\n        IStaker(staker).claimCrv(gauge);\n\n        //check if there are extra rewards\n        address stash = pool.stash;\n        if(stash != address(0)){\n            //claim extra rewards\n            IStash(stash).claimRewards();\n            //process extra rewards\n            IStash(stash).processStash();\n        }\n\n        //crv balance\n        uint256 crvBal = IERC20(crv).balanceOf(address(this));\n\n        if (crvBal > 0) {\n            // LockIncentive = cvxCrv stakers (currently 10%)\n            uint256 _lockIncentive = crvBal.mul(lockIncentive).div(FEE_DENOMINATOR);\n            // StakerIncentive = cvx stakers (currently 5%)\n            uint256 _stakerIncentive = crvBal.mul(stakerIncentive).div(FEE_DENOMINATOR);\n            // CallIncentive = caller of this contract (currently 1%)\n            uint256 _callIncentive = crvBal.mul(earmarkIncentive).div(FEE_DENOMINATOR);\n            \n            // Treasury = vlCVX (currently 1%)\n            if(treasury != address(0) && treasury != address(this) && platformFee > 0){\n                //only subtract after address condition check\n                uint256 _platform = crvBal.mul(platformFee).div(FEE_DENOMINATOR);\n                crvBal = crvBal.sub(_platform);\n                IERC20(crv).safeTransfer(treasury, _platform);\n            }\n\n            //remove incentives from balance\n            crvBal = crvBal.sub(_lockIncentive).sub(_callIncentive).sub(_stakerIncentive);\n\n            //send incentives for calling\n            IERC20(crv).safeTransfer(msg.sender, _callIncentive);          \n\n            //send crv to lp provider reward contract\n            address rewardContract = pool.crvRewards;\n            IERC20(crv).safeTransfer(rewardContract, crvBal);\n            IRewards(rewardContract).queueNewRewards(crvBal);\n\n            //send lockers' share of crv to reward contract\n            IERC20(crv).safeTransfer(lockRewards, _lockIncentive);\n            IRewards(lockRewards).queueNewRewards(_lockIncentive);\n\n            //send stakers's share of crv to reward contract\n            IERC20(crv).safeTransfer(stakerRewards, _stakerIncentive);\n        }\n    }\n\n    /**\n     * @notice Basically a hugely pivotal function.\n     *         Responsible for collecting the crv from gauge, and then redistributing to the correct place.\n     *         Pays the caller a fee to process this.\n     */\n    function earmarkRewards(uint256 _pid) external returns(bool){\n        require(!isShutdown,\"shutdown\");\n        _earmarkRewards(_pid);\n        return true;\n    }\n\n    /**\n     * @notice Claim fees from curve distro contract, put in lockers' reward contract.\n     *         lockFees is the secondary reward contract that uses the virtual balances from cvxCrv\n     */\n    function earmarkFees(address _feeToken) external returns(bool){\n        require(!isShutdown,\"shutdown\");\n        FeeDistro memory feeDistro = feeTokens[_feeToken];\n        \n        require(feeDistro.active, \"Inactive distro\");\n        require(!gaugeMap[_feeToken], \"Invalid token\");\n\n        //claim fee rewards\n        uint256 tokenBalanceBefore = IERC20(_feeToken).balanceOf(address(this));\n        IStaker(staker).claimFees(feeDistro.distro, _feeToken);\n        uint256 tokenBalanceAfter = IERC20(_feeToken).balanceOf(address(this));\n        uint256 feesClaimed = tokenBalanceAfter.sub(tokenBalanceBefore);\n\n        //send fee rewards to reward contract\n        IERC20(_feeToken).safeTransfer(feeDistro.rewards, feesClaimed);\n        IRewards(feeDistro.rewards).queueNewRewards(feesClaimed);\n\n        return true;\n    }\n\n    /**\n     * @notice Callback from reward contract when crv is received.\n     * @dev    Goes off and mints a relative amount of `CVX` based on the distribution schedule.\n     */\n    function rewardClaimed(uint256 _pid, address _address, uint256 _amount) external returns(bool){\n        address rewardContract = poolInfo[_pid].crvRewards;\n        require(msg.sender == rewardContract || msg.sender == lockRewards, \"!auth\");\n\n        //mint reward tokens\n        ITokenMinter(minter).mint(_address,_amount);\n        \n        return true;\n    }\n\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}