creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/mocks/adapters/MockGenericAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../release/extensions/integration-manager/integrations/utils/AdapterBase.sol\";\n\n/// @title IMockGenericIntegratee Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IMockGenericIntegratee {\n    function swap(\n        address[] calldata,\n        uint256[] calldata,\n        address[] calldata,\n        uint256[] calldata\n    ) external payable;\n\n    function swapOnBehalf(\n        address payable,\n        address[] calldata,\n        uint256[] calldata,\n        address[] calldata,\n        uint256[] calldata\n    ) external payable;\n}\n\n/// @title MockGenericAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Provides a generic adapter that:\n/// 1. Provides swapping functions that use various `SpendAssetsTransferType` values\n/// 2. Directly parses the _actual_ values to swap from provided call data (e.g., `actualIncomingAssetAmounts`)\n/// 3. Directly parses values needed by the IntegrationManager from provided call data (e.g., `minIncomingAssetAmounts`)\ncontract MockGenericAdapter is AdapterBase {\n    address public immutable INTEGRATEE;\n\n    // No need to specify the IntegrationManager\n    constructor(address _integratee) public AdapterBase(address(0)) {\n        INTEGRATEE = _integratee;\n    }\n\n    function identifier() external pure override returns (string memory) {\n        return \"MOCK_GENERIC\";\n    }\n\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _callArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory maxSpendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        (\n            spendAssets_,\n            maxSpendAssetAmounts_,\n            ,\n            incomingAssets_,\n            minIncomingAssetAmounts_,\n\n        ) = __decodeCallArgs(_callArgs);\n\n        return (\n            __getSpendAssetsHandleTypeForSelector(_selector),\n            spendAssets_,\n            maxSpendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @dev Assumes SpendAssetsHandleType.Transfer unless otherwise specified\n    function __getSpendAssetsHandleTypeForSelector(bytes4 _selector)\n        private\n        pure\n        returns (IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_)\n    {\n        if (_selector == bytes4(keccak256(\"removeOnly(address,bytes,bytes)\"))) {\n            return IIntegrationManager.SpendAssetsHandleType.Remove;\n        }\n        if (_selector == bytes4(keccak256(\"swapDirectFromVault(address,bytes,bytes)\"))) {\n            return IIntegrationManager.SpendAssetsHandleType.None;\n        }\n        if (_selector == bytes4(keccak256(\"swapViaApproval(address,bytes,bytes)\"))) {\n            return IIntegrationManager.SpendAssetsHandleType.Approve;\n        }\n        return IIntegrationManager.SpendAssetsHandleType.Transfer;\n    }\n\n    function removeOnly(\n        address,\n        bytes calldata,\n        bytes calldata\n    ) external {}\n\n    function swapA(\n        address _vaultProxy,\n        bytes calldata _callArgs,\n        bytes calldata _assetTransferArgs\n    ) external fundAssetsTransferHandler(_vaultProxy, _assetTransferArgs) {\n        __decodeCallArgsAndSwap(_callArgs);\n    }\n\n    function swapB(\n        address _vaultProxy,\n        bytes calldata _callArgs,\n        bytes calldata _assetTransferArgs\n    ) external fundAssetsTransferHandler(_vaultProxy, _assetTransferArgs) {\n        __decodeCallArgsAndSwap(_callArgs);\n    }\n\n    function swapDirectFromVault(\n        address _vaultProxy,\n        bytes calldata _callArgs,\n        bytes calldata\n    ) external {\n        (\n            address[] memory spendAssets,\n            ,\n            uint256[] memory actualSpendAssetAmounts,\n            address[] memory incomingAssets,\n            ,\n            uint256[] memory actualIncomingAssetAmounts\n        ) = __decodeCallArgs(_callArgs);\n\n        IMockGenericIntegratee(INTEGRATEE).swapOnBehalf(\n            payable(_vaultProxy),\n            spendAssets,\n            actualSpendAssetAmounts,\n            incomingAssets,\n            actualIncomingAssetAmounts\n        );\n    }\n\n    function swapViaApproval(\n        address _vaultProxy,\n        bytes calldata _callArgs,\n        bytes calldata _assetTransferArgs\n    ) external fundAssetsTransferHandler(_vaultProxy, _assetTransferArgs) {\n        __decodeCallArgsAndSwap(_callArgs);\n    }\n\n    function __decodeCallArgs(bytes memory _callArgs)\n        internal\n        pure\n        returns (\n            address[] memory spendAssets_,\n            uint256[] memory maxSpendAssetAmounts_,\n            uint256[] memory actualSpendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_,\n            uint256[] memory actualIncomingAssetAmounts_\n        )\n    {\n        return\n            abi.decode(\n                _callArgs,\n                (address[], uint256[], uint256[], address[], uint256[], uint256[])\n            );\n    }\n\n    function __decodeCallArgsAndSwap(bytes memory _callArgs) internal {\n        (\n            address[] memory spendAssets,\n            ,\n            uint256[] memory actualSpendAssetAmounts,\n            address[] memory incomingAssets,\n            ,\n            uint256[] memory actualIncomingAssetAmounts\n        ) = __decodeCallArgs(_callArgs);\n\n        for (uint256 i; i < spendAssets.length; i++) {\n            ERC20(spendAssets[i]).approve(INTEGRATEE, actualSpendAssetAmounts[i]);\n        }\n        IMockGenericIntegratee(INTEGRATEE).swap(\n            spendAssets,\n            actualSpendAssetAmounts,\n            incomingAssets,\n            actualIncomingAssetAmounts\n        );\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\nimport \"../../utils/Address.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    using Address for address;\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 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 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 returns (uint8) {\n        return _decimals;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view 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     * - `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 {\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"
      },
      "contracts/release/extensions/integration-manager/integrations/utils/AdapterBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../IIntegrationAdapter.sol\";\nimport \"./IntegrationSelectors.sol\";\n\n/// @title AdapterBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A base contract for integration adapters\nabstract contract AdapterBase is IIntegrationAdapter, IntegrationSelectors {\n    using SafeERC20 for ERC20;\n\n    address internal immutable INTEGRATION_MANAGER;\n\n    /// @dev Provides a standard implementation for transferring assets between\n    /// the fund's VaultProxy and the adapter, by wrapping the adapter action.\n    /// This modifier should be implemented in almost all adapter actions, unless they\n    /// do not move assets or can spend and receive assets directly with the VaultProxy\n    modifier fundAssetsTransferHandler(\n        address _vaultProxy,\n        bytes memory _encodedAssetTransferArgs\n    ) {\n        (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType,\n            address[] memory spendAssets,\n            uint256[] memory spendAssetAmounts,\n            address[] memory incomingAssets\n        ) = __decodeEncodedAssetTransferArgs(_encodedAssetTransferArgs);\n\n        // Take custody of spend assets (if necessary)\n        if (spendAssetsHandleType == IIntegrationManager.SpendAssetsHandleType.Approve) {\n            for (uint256 i = 0; i < spendAssets.length; i++) {\n                ERC20(spendAssets[i]).safeTransferFrom(\n                    _vaultProxy,\n                    address(this),\n                    spendAssetAmounts[i]\n                );\n            }\n        }\n\n        // Execute call\n        _;\n\n        // Transfer remaining assets back to the fund's VaultProxy\n        __transferContractAssetBalancesToFund(_vaultProxy, incomingAssets);\n        __transferContractAssetBalancesToFund(_vaultProxy, spendAssets);\n    }\n\n    modifier onlyIntegrationManager {\n        require(\n            msg.sender == INTEGRATION_MANAGER,\n            \"Only the IntegrationManager can call this function\"\n        );\n        _;\n    }\n\n    constructor(address _integrationManager) public {\n        INTEGRATION_MANAGER = _integrationManager;\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Helper for adapters to approve their integratees with the max amount of an asset.\n    /// Since everything is done atomically, and only the balances to-be-used are sent to adapters,\n    /// there is no need to approve exact amounts on every call.\n    function __approveMaxAsNeeded(\n        address _asset,\n        address _target,\n        uint256 _neededAmount\n    ) internal {\n        if (ERC20(_asset).allowance(address(this), _target) < _neededAmount) {\n            ERC20(_asset).approve(_target, type(uint256).max);\n        }\n    }\n\n    /// @dev Helper to decode the _encodedAssetTransferArgs param passed to adapter call\n    function __decodeEncodedAssetTransferArgs(bytes memory _encodedAssetTransferArgs)\n        internal\n        pure\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_\n        )\n    {\n        return\n            abi.decode(\n                _encodedAssetTransferArgs,\n                (IIntegrationManager.SpendAssetsHandleType, address[], uint256[], address[])\n            );\n    }\n\n    /// @dev Helper to transfer full contract balances of assets to the specified VaultProxy\n    function __transferContractAssetBalancesToFund(address _vaultProxy, address[] memory _assets)\n        private\n    {\n        for (uint256 i = 0; i < _assets.length; i++) {\n            uint256 postCallAmount = ERC20(_assets[i]).balanceOf(address(this));\n            if (postCallAmount > 0) {\n                ERC20(_assets[i]).safeTransfer(_vaultProxy, postCallAmount);\n            }\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `INTEGRATION_MANAGER` variable\n    /// @return integrationManager_ The `INTEGRATION_MANAGER` variable value\n    function getIntegrationManager() external view returns (address integrationManager_) {\n        return INTEGRATION_MANAGER;\n    }\n}\n"
      },
      "@openzeppelin/contracts/GSN/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.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"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.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/math/SafeMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.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, 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\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        return sub(a, b, \"SafeMath: subtraction overflow\");\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     * 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        uint256 c = a - b;\n\n        return c;\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        // 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) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts 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        return div(a, b, \"SafeMath: division by zero\");\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts 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        return mod(a, b, \"SafeMath: modulo by zero\");\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {\n        require(b != 0, errorMessage);\n        return a % b;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.2;\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 in 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        return _functionCallWithValue(target, data, value, errorMessage);\n    }\n\n    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {\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: weiValue }(data);\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/token/ERC20/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.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"
      },
      "contracts/release/extensions/integration-manager/integrations/IIntegrationAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../IIntegrationManager.sol\";\n\n/// @title Integration Adapter interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for all integration adapters\ninterface IIntegrationAdapter {\n    function identifier() external pure returns (string memory identifier_);\n\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        );\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/utils/IntegrationSelectors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IntegrationSelectors Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Selectors for integration actions\n/// @dev Selectors are created from their signatures rather than hardcoded for easy verification\nabstract contract IntegrationSelectors {\n    bytes4 public constant ADD_TRACKED_ASSETS_SELECTOR = bytes4(\n        keccak256(\"addTrackedAssets(address,bytes,bytes)\")\n    );\n\n    // Trading\n    bytes4 public constant TAKE_ORDER_SELECTOR = bytes4(\n        keccak256(\"takeOrder(address,bytes,bytes)\")\n    );\n\n    // Lending\n    bytes4 public constant LEND_SELECTOR = bytes4(keccak256(\"lend(address,bytes,bytes)\"));\n    bytes4 public constant REDEEM_SELECTOR = bytes4(keccak256(\"redeem(address,bytes,bytes)\"));\n}\n"
      },
      "contracts/release/extensions/integration-manager/IIntegrationManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IIntegrationManager interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for the IntegrationManager\ninterface IIntegrationManager {\n    enum SpendAssetsHandleType {None, Approve, Transfer, Remove}\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/ZeroExV2Adapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/IZeroExV2.sol\";\nimport \"../../../../utils/MathHelpers.sol\";\nimport \"../../../../utils/AddressArrayLib.sol\";\nimport \"../../../utils/FundDeployerOwnerMixin.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title ZeroExV2Adapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter to 0xV2 Exchange Contract\ncontract ZeroExV2Adapter is AdapterBase, FundDeployerOwnerMixin, MathHelpers {\n    using AddressArrayLib for address[];\n    using SafeMath for uint256;\n\n    event AllowedMakerAdded(address indexed account);\n\n    event AllowedMakerRemoved(address indexed account);\n\n    address private immutable EXCHANGE;\n    mapping(address => bool) private makerToIsAllowed;\n\n    // Gas could be optimized for the end-user by also storing an immutable ZRX_ASSET_DATA,\n    // for example, but in the narrow OTC use-case of this adapter, taker fees are unlikely.\n    constructor(\n        address _integrationManager,\n        address _exchange,\n        address _fundDeployer,\n        address[] memory _allowedMakers\n    ) public AdapterBase(_integrationManager) FundDeployerOwnerMixin(_fundDeployer) {\n        EXCHANGE = _exchange;\n        if (_allowedMakers.length > 0) {\n            __addAllowedMakers(_allowedMakers);\n        }\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ZERO_EX_V2\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        require(_selector == TAKE_ORDER_SELECTOR, \"parseAssetsForMethod: _selector invalid\");\n\n        (\n            bytes memory encodedZeroExOrderArgs,\n            uint256 takerAssetFillAmount\n        ) = __decodeTakeOrderCallArgs(_encodedCallArgs);\n        IZeroExV2.Order memory order = __constructOrderStruct(encodedZeroExOrderArgs);\n\n        require(\n            isAllowedMaker(order.makerAddress),\n            \"parseAssetsForMethod: Order maker is not allowed\"\n        );\n        require(\n            takerAssetFillAmount <= order.takerAssetAmount,\n            \"parseAssetsForMethod: Taker asset fill amount greater than available\"\n        );\n\n        address makerAsset = __getAssetAddress(order.makerAssetData);\n        address takerAsset = __getAssetAddress(order.takerAssetData);\n\n        // Format incoming assets\n        incomingAssets_ = new address[](1);\n        incomingAssets_[0] = makerAsset;\n        minIncomingAssetAmounts_ = new uint256[](1);\n        minIncomingAssetAmounts_[0] = __calcRelativeQuantity(\n            order.takerAssetAmount,\n            order.makerAssetAmount,\n            takerAssetFillAmount\n        );\n\n        if (order.takerFee > 0) {\n            address takerFeeAsset = __getAssetAddress(IZeroExV2(EXCHANGE).ZRX_ASSET_DATA());\n            uint256 takerFeeFillAmount = __calcRelativeQuantity(\n                order.takerAssetAmount,\n                order.takerFee,\n                takerAssetFillAmount\n            ); // fee calculated relative to taker fill amount\n\n            if (takerFeeAsset == makerAsset) {\n                require(\n                    order.takerFee < order.makerAssetAmount,\n                    \"parseAssetsForMethod: Fee greater than makerAssetAmount\"\n                );\n\n                spendAssets_ = new address[](1);\n                spendAssets_[0] = takerAsset;\n\n                spendAssetAmounts_ = new uint256[](1);\n                spendAssetAmounts_[0] = takerAssetFillAmount;\n\n                minIncomingAssetAmounts_[0] = minIncomingAssetAmounts_[0].sub(takerFeeFillAmount);\n            } else if (takerFeeAsset == takerAsset) {\n                spendAssets_ = new address[](1);\n                spendAssets_[0] = takerAsset;\n\n                spendAssetAmounts_ = new uint256[](1);\n                spendAssetAmounts_[0] = takerAssetFillAmount.add(takerFeeFillAmount);\n            } else {\n                spendAssets_ = new address[](2);\n                spendAssets_[0] = takerAsset;\n                spendAssets_[1] = takerFeeAsset;\n\n                spendAssetAmounts_ = new uint256[](2);\n                spendAssetAmounts_[0] = takerAssetFillAmount;\n                spendAssetAmounts_[1] = takerFeeFillAmount;\n            }\n        } else {\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = takerAsset;\n\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = takerAssetFillAmount;\n        }\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Take an order on 0x\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function takeOrder(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (\n            bytes memory encodedZeroExOrderArgs,\n            uint256 takerAssetFillAmount\n        ) = __decodeTakeOrderCallArgs(_encodedCallArgs);\n        IZeroExV2.Order memory order = __constructOrderStruct(encodedZeroExOrderArgs);\n\n        // Approve spend assets as needed\n        __approveMaxAsNeeded(\n            __getAssetAddress(order.takerAssetData),\n            __getAssetProxy(order.takerAssetData),\n            takerAssetFillAmount\n        );\n        // Ignores whether makerAsset or takerAsset overlap with the takerFee asset for simplicity\n        if (order.takerFee > 0) {\n            bytes memory zrxData = IZeroExV2(EXCHANGE).ZRX_ASSET_DATA();\n            __approveMaxAsNeeded(\n                __getAssetAddress(zrxData),\n                __getAssetProxy(zrxData),\n                __calcRelativeQuantity(\n                    order.takerAssetAmount,\n                    order.takerFee,\n                    takerAssetFillAmount\n                ) // fee calculated relative to taker fill amount\n            );\n        }\n\n        // Execute order\n        (, , , bytes memory signature) = __decodeZeroExOrderArgs(encodedZeroExOrderArgs);\n        IZeroExV2(EXCHANGE).fillOrder(order, takerAssetFillAmount, signature);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Parses user inputs into a ZeroExV2.Order format\n    function __constructOrderStruct(bytes memory _encodedOrderArgs)\n        private\n        pure\n        returns (IZeroExV2.Order memory order_)\n    {\n        (\n            address[4] memory orderAddresses,\n            uint256[6] memory orderValues,\n            bytes[2] memory orderData,\n\n        ) = __decodeZeroExOrderArgs(_encodedOrderArgs);\n\n        return\n            IZeroExV2.Order({\n                makerAddress: orderAddresses[0],\n                takerAddress: orderAddresses[1],\n                feeRecipientAddress: orderAddresses[2],\n                senderAddress: orderAddresses[3],\n                makerAssetAmount: orderValues[0],\n                takerAssetAmount: orderValues[1],\n                makerFee: orderValues[2],\n                takerFee: orderValues[3],\n                expirationTimeSeconds: orderValues[4],\n                salt: orderValues[5],\n                makerAssetData: orderData[0],\n                takerAssetData: orderData[1]\n            });\n    }\n\n    /// @dev Decode the parameters of a takeOrder call\n    /// @param _encodedCallArgs Encoded parameters passed from client side\n    /// @return encodedZeroExOrderArgs_ Encoded args of the 0x order\n    /// @return takerAssetFillAmount_ Amount of taker asset to fill\n    function __decodeTakeOrderCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (bytes memory encodedZeroExOrderArgs_, uint256 takerAssetFillAmount_)\n    {\n        return abi.decode(_encodedCallArgs, (bytes, uint256));\n    }\n\n    /// @dev Decode the parameters of a 0x order\n    /// @param _encodedZeroExOrderArgs Encoded parameters of the 0x order\n    /// @return orderAddresses_ Addresses used in the order\n    /// - [0] 0x Order param: makerAddress\n    /// - [1] 0x Order param: takerAddress\n    /// - [2] 0x Order param: feeRecipientAddress\n    /// - [3] 0x Order param: senderAddress\n    /// @return orderValues_ Values used in the order\n    /// - [0] 0x Order param: makerAssetAmount\n    /// - [1] 0x Order param: takerAssetAmount\n    /// - [2] 0x Order param: makerFee\n    /// - [3] 0x Order param: takerFee\n    /// - [4] 0x Order param: expirationTimeSeconds\n    /// - [5] 0x Order param: salt\n    /// @return orderData_ Bytes data used in the order\n    /// - [0] 0x Order param: makerAssetData\n    /// - [1] 0x Order param: takerAssetData\n    /// @return signature_ Signature of the order\n    function __decodeZeroExOrderArgs(bytes memory _encodedZeroExOrderArgs)\n        private\n        pure\n        returns (\n            address[4] memory orderAddresses_,\n            uint256[6] memory orderValues_,\n            bytes[2] memory orderData_,\n            bytes memory signature_\n        )\n    {\n        return abi.decode(_encodedZeroExOrderArgs, (address[4], uint256[6], bytes[2], bytes));\n    }\n\n    /// @dev Parses the asset address from 0x assetData\n    function __getAssetAddress(bytes memory _assetData)\n        private\n        pure\n        returns (address assetAddress_)\n    {\n        assembly {\n            assetAddress_ := mload(add(_assetData, 36))\n        }\n    }\n\n    /// @dev Gets the 0x assetProxy address for an ERC20 token\n    function __getAssetProxy(bytes memory _assetData) private view returns (address assetProxy_) {\n        bytes4 assetProxyId;\n\n        assembly {\n            assetProxyId := and(\n                mload(add(_assetData, 32)),\n                0xFFFFFFFF00000000000000000000000000000000000000000000000000000000\n            )\n        }\n        assetProxy_ = IZeroExV2(EXCHANGE).getAssetProxy(assetProxyId);\n    }\n\n    /////////////////////////////\n    // ALLOWED MAKERS REGISTRY //\n    /////////////////////////////\n\n    /// @notice Adds accounts to the list of allowed 0x order makers\n    /// @param _accountsToAdd Accounts to add\n    function addAllowedMakers(address[] calldata _accountsToAdd) external onlyFundDeployerOwner {\n        __addAllowedMakers(_accountsToAdd);\n    }\n\n    /// @notice Removes accounts from the list of allowed 0x order makers\n    /// @param _accountsToRemove Accounts to remove\n    function removeAllowedMakers(address[] calldata _accountsToRemove)\n        external\n        onlyFundDeployerOwner\n    {\n        require(_accountsToRemove.length > 0, \"removeAllowedMakers: Empty _accountsToRemove\");\n\n        for (uint256 i; i < _accountsToRemove.length; i++) {\n            require(\n                isAllowedMaker(_accountsToRemove[i]),\n                \"removeAllowedMakers: Account is not an allowed maker\"\n            );\n\n            makerToIsAllowed[_accountsToRemove[i]] = false;\n\n            emit AllowedMakerRemoved(_accountsToRemove[i]);\n        }\n    }\n\n    /// @dev Helper to add accounts to the list of allowed makers\n    function __addAllowedMakers(address[] memory _accountsToAdd) private {\n        require(_accountsToAdd.length > 0, \"__addAllowedMakers: Empty _accountsToAdd\");\n\n        for (uint256 i; i < _accountsToAdd.length; i++) {\n            require(!isAllowedMaker(_accountsToAdd[i]), \"__addAllowedMakers: Value already set\");\n\n            makerToIsAllowed[_accountsToAdd[i]] = true;\n\n            emit AllowedMakerAdded(_accountsToAdd[i]);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `EXCHANGE` variable value\n    /// @return exchange_ The `EXCHANGE` variable value\n    function getExchange() external view returns (address exchange_) {\n        return EXCHANGE;\n    }\n\n    /// @notice Checks whether an account is an allowed maker of 0x orders\n    /// @param _who The account to check\n    /// @return isAllowedMaker_ True if _who is an allowed maker\n    function isAllowedMaker(address _who) public view returns (bool isAllowedMaker_) {\n        return makerToIsAllowed[_who];\n    }\n}\n"
      },
      "contracts/release/interfaces/IZeroExV2.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n/// @dev Minimal interface for our interactions with the ZeroEx Exchange contract\ninterface IZeroExV2 {\n    struct Order {\n        address makerAddress;\n        address takerAddress;\n        address feeRecipientAddress;\n        address senderAddress;\n        uint256 makerAssetAmount;\n        uint256 takerAssetAmount;\n        uint256 makerFee;\n        uint256 takerFee;\n        uint256 expirationTimeSeconds;\n        uint256 salt;\n        bytes makerAssetData;\n        bytes takerAssetData;\n    }\n\n    struct OrderInfo {\n        uint8 orderStatus;\n        bytes32 orderHash;\n        uint256 orderTakerAssetFilledAmount;\n    }\n\n    struct FillResults {\n        uint256 makerAssetFilledAmount;\n        uint256 takerAssetFilledAmount;\n        uint256 makerFeePaid;\n        uint256 takerFeePaid;\n    }\n\n    function ZRX_ASSET_DATA() external view returns (bytes memory);\n\n    function filled(bytes32) external view returns (uint256);\n\n    function cancelled(bytes32) external view returns (bool);\n\n    function getOrderInfo(Order calldata) external view returns (OrderInfo memory);\n\n    function getAssetProxy(bytes4) external view returns (address);\n\n    function isValidSignature(\n        bytes32,\n        address,\n        bytes calldata\n    ) external view returns (bool);\n\n    function preSign(\n        bytes32,\n        address,\n        bytes calldata\n    ) external;\n\n    function cancelOrder(Order calldata) external;\n\n    function fillOrder(\n        Order calldata,\n        uint256,\n        bytes calldata\n    ) external returns (FillResults memory);\n}\n"
      },
      "contracts/release/utils/MathHelpers.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\n/// @title MathHelpers Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Helper functions for common math operations\nabstract contract MathHelpers {\n    using SafeMath for uint256;\n\n    /// @dev Calculates a proportional value relative to a known ratio\n    function __calcRelativeQuantity(\n        uint256 _quantity1,\n        uint256 _quantity2,\n        uint256 _relativeQuantity1\n    ) internal pure returns (uint256 relativeQuantity2_) {\n        return _relativeQuantity1.mul(_quantity2).div(_quantity1);\n    }\n\n    /// @dev Calculates a rate normalized to 10^18 precision,\n    /// for given base and quote asset decimals and amounts\n    function __calcNormalizedRate(\n        uint256 _baseAssetDecimals,\n        uint256 _baseAssetAmount,\n        uint256 _quoteAssetDecimals,\n        uint256 _quoteAssetAmount\n    ) internal pure returns (uint256 normalizedRate_) {\n        return\n            _quoteAssetAmount.mul(10**_baseAssetDecimals.add(18)).div(\n                _baseAssetAmount.mul(10**_quoteAssetDecimals)\n            );\n    }\n}\n"
      },
      "contracts/release/utils/AddressArrayLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title AddressArray Library\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A library to extend the address array data type\nlibrary AddressArrayLib {\n    /// @dev Helper to verify if an array contains a particular value\n    function contains(address[] memory _self, address _target)\n        internal\n        pure\n        returns (bool doesContain_)\n    {\n        for (uint256 i; i < _self.length; i++) {\n            if (_target == _self[i]) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /// @dev Helper to verify if array is a set of unique values.\n    /// Does not assert length > 0.\n    function isUniqueSet(address[] memory _self) internal pure returns (bool isUnique_) {\n        if (_self.length <= 1) {\n            return true;\n        }\n\n        uint256 arrayLength = _self.length;\n        for (uint256 i; i < arrayLength; i++) {\n            for (uint256 j = i + 1; j < arrayLength; j++) {\n                if (_self[i] == _self[j]) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /// @dev Helper to remove items from an array. Removes all matching occurrences of each item.\n    /// Does not assert uniqueness of either array.\n    function removeItems(address[] memory _self, address[] memory _itemsToRemove)\n        internal\n        pure\n        returns (address[] memory nextArray_)\n    {\n        if (_itemsToRemove.length == 0) {\n            return _self;\n        }\n\n        bool[] memory indexesToRemove = new bool[](_self.length);\n        uint256 remainingItemsCount = _self.length;\n        for (uint256 i; i < _self.length; i++) {\n            if (contains(_itemsToRemove, _self[i])) {\n                indexesToRemove[i] = true;\n                remainingItemsCount--;\n            }\n        }\n\n        if (remainingItemsCount == _self.length) {\n            nextArray_ = _self;\n        } else if (remainingItemsCount > 0) {\n            nextArray_ = new address[](remainingItemsCount);\n            uint256 nextArrayIndex;\n            for (uint256 i; i < _self.length; i++) {\n                if (!indexesToRemove[i]) {\n                    nextArray_[nextArrayIndex] = _self[i];\n                    nextArrayIndex++;\n                }\n            }\n        }\n\n        return nextArray_;\n    }\n}\n"
      },
      "contracts/release/extensions/utils/FundDeployerOwnerMixin.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../core/fund-deployer/IFundDeployer.sol\";\n\n/// @title FundDeployerOwnerMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract that defers ownership to the owner of FundDeployer\nabstract contract FundDeployerOwnerMixin {\n    address internal immutable FUND_DEPLOYER;\n\n    modifier onlyFundDeployerOwner() {\n        require(\n            msg.sender == getOwner(),\n            \"onlyFundDeployerOwner: Only the FundDeployer owner can call this function\"\n        );\n        _;\n    }\n\n    constructor(address _fundDeployer) public {\n        FUND_DEPLOYER = _fundDeployer;\n    }\n\n    /// @notice Gets the owner of this contract\n    /// @return owner_ The owner\n    /// @dev Ownership is deferred to the owner of the FundDeployer contract\n    function getOwner() public view returns (address owner_) {\n        return IFundDeployer(FUND_DEPLOYER).getOwner();\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `FUND_DEPLOYER` variable\n    /// @return fundDeployer_ The `FUND_DEPLOYER` variable value\n    function getFundDeployer() external view returns (address fundDeployer_) {\n        return FUND_DEPLOYER;\n    }\n}\n"
      },
      "contracts/release/core/fund-deployer/IFundDeployer.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IFundDeployer Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IFundDeployer {\n    enum ReleaseStatus {PreLaunch, Live, Paused}\n\n    function getOwner() external view returns (address);\n\n    function getReleaseStatus() external view returns (ReleaseStatus);\n\n    function isRegisteredVaultCall(address, bytes4) external view returns (bool);\n}\n"
      },
      "contracts/release/extensions/policy-manager/PolicyManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/utils/EnumerableSet.sol\";\nimport \"../../core/fund/vault/IVault.sol\";\nimport \"../utils/ExtensionBase.sol\";\nimport \"../utils/FundDeployerOwnerMixin.sol\";\nimport \"./IPolicy.sol\";\nimport \"./IPolicyManager.sol\";\n\n/// @title PolicyManager Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Manages policies for funds\ncontract PolicyManager is IPolicyManager, ExtensionBase, FundDeployerOwnerMixin {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    event PolicyDeregistered(address indexed policy, string indexed identifier);\n\n    event PolicyDisabledForFund(address indexed comptrollerProxy, address indexed policy);\n\n    event PolicyEnabledForFund(\n        address indexed comptrollerProxy,\n        address indexed policy,\n        bytes settingsData\n    );\n\n    event PolicyRegistered(\n        address indexed policy,\n        string indexed identifier,\n        PolicyHook[] implementedHooks\n    );\n\n    EnumerableSet.AddressSet private registeredPolicies;\n    mapping(address => mapping(PolicyHook => bool)) private policyToHookToIsImplemented;\n    mapping(address => EnumerableSet.AddressSet) private comptrollerProxyToPolicies;\n\n    modifier onlyBuySharesHooks(address _policy) {\n        require(\n            !policyImplementsHook(_policy, PolicyHook.PreCallOnIntegration) &&\n                !policyImplementsHook(_policy, PolicyHook.PostCallOnIntegration),\n            \"onlyBuySharesHooks: Disallowed hook\"\n        );\n        _;\n    }\n\n    modifier onlyEnabledPolicyForFund(address _comptrollerProxy, address _policy) {\n        require(\n            policyIsEnabledForFund(_comptrollerProxy, _policy),\n            \"onlyEnabledPolicyForFund: Policy not enabled\"\n        );\n        _;\n    }\n\n    constructor(address _fundDeployer) public FundDeployerOwnerMixin(_fundDeployer) {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Validates and initializes policies as necessary prior to fund activation\n    /// @param _isMigratedFund True if the fund is migrating to this release\n    /// @dev Caller is expected to be a valid ComptrollerProxy, but there isn't a need to validate.\n    function activateForFund(bool _isMigratedFund) external override {\n        address vaultProxy = __setValidatedVaultProxy(msg.sender);\n\n        // Policies must assert that they are congruent with migrated vault state\n        if (_isMigratedFund) {\n            address[] memory enabledPolicies = getEnabledPoliciesForFund(msg.sender);\n            for (uint256 i; i < enabledPolicies.length; i++) {\n                __activatePolicyForFund(msg.sender, vaultProxy, enabledPolicies[i]);\n            }\n        }\n    }\n\n    /// @notice Deactivates policies for a fund by destroying storage\n    function deactivateForFund() external override {\n        delete comptrollerProxyToVaultProxy[msg.sender];\n\n        for (uint256 i = comptrollerProxyToPolicies[msg.sender].length(); i > 0; i--) {\n            comptrollerProxyToPolicies[msg.sender].remove(\n                comptrollerProxyToPolicies[msg.sender].at(i - 1)\n            );\n        }\n    }\n\n    /// @notice Disables a policy for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _policy The policy address to disable\n    function disablePolicyForFund(address _comptrollerProxy, address _policy)\n        external\n        onlyBuySharesHooks(_policy)\n        onlyEnabledPolicyForFund(_comptrollerProxy, _policy)\n    {\n        __validateIsFundOwner(getVaultProxyForFund(_comptrollerProxy), msg.sender);\n\n        comptrollerProxyToPolicies[_comptrollerProxy].remove(_policy);\n\n        emit PolicyDisabledForFund(_comptrollerProxy, _policy);\n    }\n\n    /// @notice Enables a policy for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _policy The policy address to enable\n    /// @param _settingsData The encoded settings data with which to configure the policy\n    /// @dev Disabling a policy does not delete fund config on the policy, so if a policy is\n    /// disabled and then enabled again, its initial state will be the previous config. It is the\n    /// policy's job to determine how to merge that config with the _settingsData param in this function.\n    function enablePolicyForFund(\n        address _comptrollerProxy,\n        address _policy,\n        bytes calldata _settingsData\n    ) external onlyBuySharesHooks(_policy) {\n        address vaultProxy = getVaultProxyForFund(_comptrollerProxy);\n        __validateIsFundOwner(vaultProxy, msg.sender);\n\n        __enablePolicyForFund(_comptrollerProxy, _policy, _settingsData);\n\n        __activatePolicyForFund(_comptrollerProxy, vaultProxy, _policy);\n    }\n\n    /// @notice Enable policies for use in a fund\n    /// @param _configData Encoded config data\n    /// @dev Only called during init() on ComptrollerProxy deployment\n    function setConfigForFund(bytes calldata _configData) external override {\n        (address[] memory policies, bytes[] memory settingsData) = abi.decode(\n            _configData,\n            (address[], bytes[])\n        );\n\n        // Sanity check\n        require(\n            policies.length == settingsData.length,\n            \"setConfigForFund: policies and settingsData array lengths unequal\"\n        );\n\n        // Enable each policy with settings\n        for (uint256 i; i < policies.length; i++) {\n            __enablePolicyForFund(msg.sender, policies[i], settingsData[i]);\n        }\n    }\n\n    /// @notice Updates policy settings for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _policy The Policy contract to update\n    /// @param _settingsData The encoded settings data with which to update the policy config\n    function updatePolicySettingsForFund(\n        address _comptrollerProxy,\n        address _policy,\n        bytes calldata _settingsData\n    ) external onlyBuySharesHooks(_policy) onlyEnabledPolicyForFund(_comptrollerProxy, _policy) {\n        address vaultProxy = getVaultProxyForFund(_comptrollerProxy);\n        __validateIsFundOwner(vaultProxy, msg.sender);\n\n        IPolicy(_policy).updateFundSettings(_comptrollerProxy, vaultProxy, _settingsData);\n    }\n\n    /// @notice Validates all policies that apply to a given hook for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _hook The PolicyHook for which to validate policies\n    /// @param _validationData The encoded data with which to validate the filtered policies\n    function validatePolicies(\n        address _comptrollerProxy,\n        PolicyHook _hook,\n        bytes calldata _validationData\n    ) external override {\n        address vaultProxy = getVaultProxyForFund(_comptrollerProxy);\n        address[] memory policies = getEnabledPoliciesForFund(_comptrollerProxy);\n        for (uint256 i; i < policies.length; i++) {\n            if (!policyImplementsHook(policies[i], _hook)) {\n                continue;\n            }\n\n            require(\n                IPolicy(policies[i]).validateRule(\n                    _comptrollerProxy,\n                    vaultProxy,\n                    _hook,\n                    _validationData\n                ),\n                string(\n                    abi.encodePacked(\n                        \"Rule evaluated to false: \",\n                        IPolicy(policies[i]).identifier()\n                    )\n                )\n            );\n        }\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to activate a policy for a fund\n    function __activatePolicyForFund(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        address _policy\n    ) private {\n        IPolicy(_policy).activateForFund(_comptrollerProxy, _vaultProxy);\n    }\n\n    /// @dev Helper to set config and enable policies for a fund\n    function __enablePolicyForFund(\n        address _comptrollerProxy,\n        address _policy,\n        bytes memory _settingsData\n    ) private {\n        require(\n            !policyIsEnabledForFund(_comptrollerProxy, _policy),\n            \"__enablePolicyForFund: policy already enabled\"\n        );\n        require(policyIsRegistered(_policy), \"__enablePolicyForFund: Policy is not registered\");\n\n        // Set fund config on policy\n        if (_settingsData.length > 0) {\n            IPolicy(_policy).addFundSettings(_comptrollerProxy, _settingsData);\n        }\n\n        // Add policy\n        comptrollerProxyToPolicies[_comptrollerProxy].add(_policy);\n\n        emit PolicyEnabledForFund(_comptrollerProxy, _policy, _settingsData);\n    }\n\n    /// @dev Helper to validate fund owner.\n    /// Preferred to a modifier because allows gas savings if re-using _vaultProxy.\n    function __validateIsFundOwner(address _vaultProxy, address _who) private view {\n        require(\n            _who == IVault(_vaultProxy).getOwner(),\n            \"Only the fund owner can call this function\"\n        );\n    }\n\n    ///////////////////////\n    // POLICIES REGISTRY //\n    ///////////////////////\n\n    /// @notice Remove policies from the list of registered policies\n    /// @param _policies Addresses of policies to be registered\n    function deregisterPolicies(address[] calldata _policies) external onlyFundDeployerOwner {\n        require(_policies.length > 0, \"deregisterPolicies: _policies cannot be empty\");\n\n        for (uint256 i; i < _policies.length; i++) {\n            require(\n                policyIsRegistered(_policies[i]),\n                \"deregisterPolicies: policy is not registered\"\n            );\n\n            registeredPolicies.remove(_policies[i]);\n\n            emit PolicyDeregistered(_policies[i], IPolicy(_policies[i]).identifier());\n        }\n    }\n\n    /// @notice Add policies to the list of registered policies\n    /// @param _policies Addresses of policies to be registered\n    function registerPolicies(address[] calldata _policies) external onlyFundDeployerOwner {\n        require(_policies.length > 0, \"registerPolicies: _policies cannot be empty\");\n\n        for (uint256 i; i < _policies.length; i++) {\n            require(\n                !policyIsRegistered(_policies[i]),\n                \"registerPolicies: policy already registered\"\n            );\n\n            registeredPolicies.add(_policies[i]);\n\n            // Store the hooks that a policy implements for later use.\n            // Fronts the gas for calls to check if a hook is implemented, and guarantees\n            // that the implementsHooks return value does not change post-registration.\n            IPolicy policyContract = IPolicy(_policies[i]);\n            PolicyHook[] memory implementedHooks = policyContract.implementedHooks();\n            for (uint256 j; j < implementedHooks.length; j++) {\n                policyToHookToIsImplemented[_policies[i]][implementedHooks[j]] = true;\n            }\n\n            emit PolicyRegistered(_policies[i], policyContract.identifier(), implementedHooks);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Get all registered policies\n    /// @return registeredPoliciesArray_ A list of all registered policy addresses\n    function getRegisteredPolicies()\n        external\n        view\n        returns (address[] memory registeredPoliciesArray_)\n    {\n        registeredPoliciesArray_ = new address[](registeredPolicies.length());\n        for (uint256 i; i < registeredPoliciesArray_.length; i++) {\n            registeredPoliciesArray_[i] = registeredPolicies.at(i);\n        }\n    }\n\n    /// @notice Get a list of enabled policies for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return enabledPolicies_ An array of enabled policy addresses\n    function getEnabledPoliciesForFund(address _comptrollerProxy)\n        public\n        view\n        returns (address[] memory enabledPolicies_)\n    {\n        enabledPolicies_ = new address[](comptrollerProxyToPolicies[_comptrollerProxy].length());\n        for (uint256 i; i < enabledPolicies_.length; i++) {\n            enabledPolicies_[i] = comptrollerProxyToPolicies[_comptrollerProxy].at(i);\n        }\n    }\n\n    /// @notice Checks if a policy implements a particular hook\n    /// @param _policy The address of the policy to check\n    /// @param _hook The PolicyHook to check\n    /// @return implementsHook_ True if the policy implements the hook\n    function policyImplementsHook(address _policy, PolicyHook _hook)\n        public\n        view\n        returns (bool implementsHook_)\n    {\n        return policyToHookToIsImplemented[_policy][_hook];\n    }\n\n    /// @notice Check if a policy is enabled for the fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund to check\n    /// @param _policy The address of the policy to check\n    /// @return isEnabled_ True if the policy is enabled for the fund\n    function policyIsEnabledForFund(address _comptrollerProxy, address _policy)\n        public\n        view\n        returns (bool isEnabled_)\n    {\n        return comptrollerProxyToPolicies[_comptrollerProxy].contains(_policy);\n    }\n\n    /// @notice Check whether a policy is registered\n    /// @param _policy The address of the policy to check\n    /// @return isRegistered_ True if the policy is registered\n    function policyIsRegistered(address _policy) public view returns (bool isRegistered_) {\n        return registeredPolicies.contains(_policy);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/EnumerableSet.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`\n * (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping (bytes32 => uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) { // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs\n            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.\n\n            bytes32 lastvalue = set._values[lastIndex];\n\n            // Move the last value to the index where the value to delete is\n            set._values[toDeleteIndex] = lastvalue;\n            // Update the index for the moved value\n            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n   /**\n    * @dev Returns the value stored at position `index` in the set. O(1).\n    *\n    * Note that there are no guarantees on the ordering of values inside the\n    * array, and it may change when more values are added or removed.\n    *\n    * Requirements:\n    *\n    * - `index` must be strictly less than {length}.\n    */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        require(set._values.length > index, \"EnumerableSet: index out of bounds\");\n        return set._values[index];\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(value)));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(value)));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(value)));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n   /**\n    * @dev Returns the value stored at position `index` in the set. O(1).\n    *\n    * Note that there are no guarantees on the ordering of values inside the\n    * array, and it may change when more values are added or removed.\n    *\n    * Requirements:\n    *\n    * - `index` must be strictly less than {length}.\n    */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint256(_at(set._inner, index)));\n    }\n\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n   /**\n    * @dev Returns the value stored at position `index` in the set. O(1).\n    *\n    * Note that there are no guarantees on the ordering of values inside the\n    * array, and it may change when more values are added or removed.\n    *\n    * Requirements:\n    *\n    * - `index` must be strictly less than {length}.\n    */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n}\n"
      },
      "contracts/release/core/fund/vault/IVault.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../persistent/utils/IMigratableVault.sol\";\n\n/// @title IVault Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IVault is IMigratableVault {\n    function addTrackedAsset(address) external;\n\n    function approveAssetSpender(\n        address,\n        address,\n        uint256\n    ) external;\n\n    function burnShares(address, uint256) external;\n\n    function callOnContract(address, bytes calldata) external;\n\n    function getAccessor() external view returns (address);\n\n    function getOwner() external view returns (address);\n\n    function getTrackedAssets() external view returns (address[] memory);\n\n    function isTrackedAsset(address) external view returns (bool);\n\n    function mintShares(address, uint256) external;\n\n    function removeTrackedAsset(address) external;\n\n    function transferShares(\n        address,\n        address,\n        uint256\n    ) external;\n\n    function withdrawAssetTo(\n        address,\n        address,\n        uint256\n    ) external;\n}\n"
      },
      "contracts/release/extensions/utils/ExtensionBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../core/fund/comptroller/IComptroller.sol\";\nimport \"../../core/fund/vault/IVault.sol\";\nimport \"../IExtension.sol\";\n\n/// @title ExtensionBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Base class for an extension\nabstract contract ExtensionBase is IExtension {\n    mapping(address => address) internal comptrollerProxyToVaultProxy;\n\n    /// @notice Allows extension to run logic during fund activation\n    /// @dev Unimplemented by default, may be overridden.\n    function activateForFund(bool) external virtual override {\n        return;\n    }\n\n    /// @notice Allows extension to run logic during fund deactivation (destruct)\n    /// @dev Unimplemented by default, may be overridden.\n    function deactivateForFund() external virtual override {\n        return;\n    }\n\n    /// @notice Receives calls from ComptrollerLib.callOnExtension()\n    /// and dispatches the appropriate action\n    /// @dev Unimplemented by default, may be overridden.\n    function receiveCallFromComptroller(\n        address,\n        uint256,\n        bytes calldata\n    ) external virtual override {\n        revert(\"receiveCallFromComptroller: Unimplemented for Extension\");\n    }\n\n    /// @notice Allows extension to run logic during fund configuration\n    /// @dev Unimplemented by default, may be overridden.\n    function setConfigForFund(bytes calldata) external virtual override {\n        return;\n    }\n\n    /// @dev Helper to validate a ComptrollerProxy-VaultProxy relation, which we store for both\n    /// gas savings and to guarantee a spoofed ComptrollerProxy does not change getVaultProxy().\n    /// Will revert without reason if the expected interfaces do not exist.\n    function __setValidatedVaultProxy(address _comptrollerProxy)\n        internal\n        returns (address vaultProxy_)\n    {\n        require(\n            comptrollerProxyToVaultProxy[_comptrollerProxy] == address(0),\n            \"__setValidatedVaultProxy: Already set\"\n        );\n\n        vaultProxy_ = IComptroller(_comptrollerProxy).getVaultProxy();\n        require(vaultProxy_ != address(0), \"__setValidatedVaultProxy: Missing vaultProxy\");\n\n        require(\n            _comptrollerProxy == IVault(vaultProxy_).getAccessor(),\n            \"__setValidatedVaultProxy: Not the VaultProxy accessor\"\n        );\n\n        comptrollerProxyToVaultProxy[_comptrollerProxy] = vaultProxy_;\n\n        return vaultProxy_;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the verified VaultProxy for a given ComptrollerProxy\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return vaultProxy_ The VaultProxy of the fund\n    function getVaultProxyForFund(address _comptrollerProxy)\n        public\n        view\n        returns (address vaultProxy_)\n    {\n        return comptrollerProxyToVaultProxy[_comptrollerProxy];\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/IPolicy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./IPolicyManager.sol\";\n\n/// @title Policy Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IPolicy {\n    function activateForFund(address _comptrollerProxy, address _vaultProxy) external;\n\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings) external;\n\n    function identifier() external pure returns (string memory identifier_);\n\n    function implementedHooks()\n        external\n        view\n        returns (IPolicyManager.PolicyHook[] memory implementedHooks_);\n\n    function updateFundSettings(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        bytes calldata _encodedSettings\n    ) external;\n\n    function validateRule(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IPolicyManager.PolicyHook _hook,\n        bytes calldata _encodedArgs\n    ) external returns (bool isValid_);\n}\n"
      },
      "contracts/release/extensions/policy-manager/IPolicyManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n/// @title PolicyManager Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for the PolicyManager\ninterface IPolicyManager {\n    enum PolicyHook {\n        BuySharesSetup,\n        PreBuyShares,\n        PostBuyShares,\n        BuySharesCompleted,\n        PreCallOnIntegration,\n        PostCallOnIntegration\n    }\n\n    function validatePolicies(\n        address,\n        PolicyHook,\n        bytes calldata\n    ) external;\n}\n"
      },
      "contracts/persistent/utils/IMigratableVault.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IMigratableVault Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @dev DO NOT EDIT CONTRACT\ninterface IMigratableVault {\n    function canMigrate(address _who) external view returns (bool canMigrate_);\n\n    function init(\n        address _owner,\n        address _accessor,\n        string calldata _fundName\n    ) external;\n\n    function setAccessor(address _nextAccessor) external;\n\n    function setVaultLib(address _nextVaultLib) external;\n}\n"
      },
      "contracts/release/core/fund/comptroller/IComptroller.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IComptroller Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IComptroller {\n    enum VaultAction {\n        None,\n        BurnShares,\n        MintShares,\n        TransferShares,\n        ApproveAssetSpender,\n        WithdrawAssetTo,\n        AddTrackedAsset,\n        RemoveTrackedAsset\n    }\n\n    function activate(address, bool) external;\n\n    function calcGav(bool) external returns (uint256, bool);\n\n    function calcGrossShareValue(bool) external returns (uint256, bool);\n\n    function callOnExtension(\n        address,\n        uint256,\n        bytes calldata\n    ) external;\n\n    function configureExtensions(bytes calldata, bytes calldata) external;\n\n    function destruct() external;\n\n    function getDenominationAsset() external view returns (address);\n\n    function getVaultProxy() external view returns (address);\n\n    function init(address, uint256) external;\n\n    function permissionedVaultAction(VaultAction, bytes calldata) external;\n}\n"
      },
      "contracts/release/extensions/IExtension.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IExtension Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for all extensions\ninterface IExtension {\n    function activateForFund(bool _isMigration) external;\n\n    function deactivateForFund() external;\n\n    function receiveCallFromComptroller(\n        address _comptrollerProxy,\n        uint256 _actionId,\n        bytes calldata _callArgs\n    ) external;\n\n    function setConfigForFund(bytes calldata _configData) external;\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/utils/PolicyBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../IPolicy.sol\";\n\n/// @title PolicyBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Abstract base contract for all policies\nabstract contract PolicyBase is IPolicy {\n    address internal immutable POLICY_MANAGER;\n\n    modifier onlyPolicyManager {\n        require(msg.sender == POLICY_MANAGER, \"Only the PolicyManager can make this call\");\n        _;\n    }\n\n    constructor(address _policyManager) public {\n        POLICY_MANAGER = _policyManager;\n    }\n\n    /// @notice Validates and initializes a policy as necessary prior to fund activation\n    /// @dev Unimplemented by default, can be overridden by the policy\n    function activateForFund(address, address) external virtual override {\n        return;\n    }\n\n    /// @notice Updates the policy settings for a fund\n    /// @dev Disallowed by default, can be overridden by the policy\n    function updateFundSettings(\n        address,\n        address,\n        bytes calldata\n    ) external virtual override {\n        revert(\"updateFundSettings: Updates not allowed for this policy\");\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `POLICY_MANAGER` variable value\n    /// @return policyManager_ The `POLICY_MANAGER` variable value\n    function getPolicyManager() external view returns (address policyManager_) {\n        return POLICY_MANAGER;\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/utils/PostCallOnIntegrationValidatePolicyBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/PolicyBase.sol\";\n\n/// @title CallOnIntegrationPostValidatePolicyMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract for policies that only implement the PostCallOnIntegration policy hook\nabstract contract PostCallOnIntegrationValidatePolicyBase is PolicyBase {\n    /// @notice Gets the implemented PolicyHooks for a policy\n    /// @return implementedHooks_ The implemented PolicyHooks\n    function implementedHooks()\n        external\n        view\n        override\n        returns (IPolicyManager.PolicyHook[] memory implementedHooks_)\n    {\n        implementedHooks_ = new IPolicyManager.PolicyHook[](1);\n        implementedHooks_[0] = IPolicyManager.PolicyHook.PostCallOnIntegration;\n\n        return implementedHooks_;\n    }\n\n    /// @notice Helper to decode rule arguments\n    function __decodeRuleArgs(bytes memory _encodedRuleArgs)\n        internal\n        pure\n        returns (\n            address adapter_,\n            bytes4 selector_,\n            address[] memory incomingAssets_,\n            uint256[] memory incomingAssetAmounts_,\n            address[] memory outgoingAssets_,\n            uint256[] memory outgoingAssetAmounts_\n        )\n    {\n        return\n            abi.decode(\n                _encodedRuleArgs,\n                (address, bytes4, address[], uint256[], address[], uint256[])\n            );\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/MaxConcentration.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../../../../core/fund/vault/VaultLib.sol\";\nimport \"../../../../infrastructure/value-interpreter/ValueInterpreter.sol\";\nimport \"./utils/PostCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title MaxConcentration Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that defines a configurable threshold for the concentration of any one asset\n/// in a fund's holdings\ncontract MaxConcentration is PostCallOnIntegrationValidatePolicyBase {\n    using SafeMath for uint256;\n\n    event MaxConcentrationSet(address indexed comptrollerProxy, uint256 value);\n\n    uint256 private constant ONE_HUNDRED_PERCENT = 10**18; // 100%\n\n    address private immutable VALUE_INTERPRETER;\n\n    mapping(address => uint256) private comptrollerProxyToMaxConcentration;\n\n    constructor(address _policyManager, address _valueInterpreter)\n        public\n        PolicyBase(_policyManager)\n    {\n        VALUE_INTERPRETER = _valueInterpreter;\n    }\n\n    /// @notice Validates and initializes a policy as necessary prior to fund activation\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _vaultProxy The fund's VaultProxy address\n    /// @dev No need to authenticate access, as there are no state transitions\n    function activateForFund(address _comptrollerProxy, address _vaultProxy)\n        external\n        override\n        onlyPolicyManager\n    {\n        require(\n            passesRule(_comptrollerProxy, _vaultProxy, VaultLib(_vaultProxy).getTrackedAssets()),\n            \"activateForFund: Max concentration exceeded\"\n        );\n    }\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        uint256 maxConcentration = abi.decode(_encodedSettings, (uint256));\n        require(maxConcentration > 0, \"addFundSettings: maxConcentration must be greater than 0\");\n        require(\n            maxConcentration <= ONE_HUNDRED_PERCENT,\n            \"addFundSettings: maxConcentration cannot exceed 100%\"\n        );\n\n        comptrollerProxyToMaxConcentration[_comptrollerProxy] = maxConcentration;\n\n        emit MaxConcentrationSet(_comptrollerProxy, maxConcentration);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"MAX_CONCENTRATION\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _vaultProxy The fund's VaultProxy address\n    /// @param _assets The assets with which to check the rule\n    /// @return isValid_ True if the rule passes\n    /// @dev The fund's denomination asset is exempt from the policy limit.\n    function passesRule(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        address[] memory _assets\n    ) public returns (bool isValid_) {\n        uint256 maxConcentration = comptrollerProxyToMaxConcentration[_comptrollerProxy];\n        ComptrollerLib comptrollerProxyContract = ComptrollerLib(_comptrollerProxy);\n        address denominationAsset = comptrollerProxyContract.getDenominationAsset();\n        // Does not require asset finality, otherwise will fail when incoming asset is a Synth\n        (uint256 totalGav, bool gavIsValid) = comptrollerProxyContract.calcGav(false);\n        if (!gavIsValid) {\n            return false;\n        }\n\n        for (uint256 i = 0; i < _assets.length; i++) {\n            address asset = _assets[i];\n            if (\n                !__rulePassesForAsset(\n                    _vaultProxy,\n                    denominationAsset,\n                    maxConcentration,\n                    totalGav,\n                    asset\n                )\n            ) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _vaultProxy The fund's VaultProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (, , address[] memory incomingAssets, , , ) = __decodeRuleArgs(_encodedArgs);\n        if (incomingAssets.length == 0) {\n            return true;\n        }\n\n        return passesRule(_comptrollerProxy, _vaultProxy, incomingAssets);\n    }\n\n    /// @dev Helper to check if the rule holds for a particular asset.\n    /// Avoids the stack-too-deep error.\n    function __rulePassesForAsset(\n        address _vaultProxy,\n        address _denominationAsset,\n        uint256 _maxConcentration,\n        uint256 _totalGav,\n        address _incomingAsset\n    ) private returns (bool isValid_) {\n        if (_incomingAsset == _denominationAsset) return true;\n\n        uint256 assetBalance = ERC20(_incomingAsset).balanceOf(_vaultProxy);\n        (uint256 assetGav, bool assetGavIsValid) = ValueInterpreter(VALUE_INTERPRETER)\n            .calcLiveAssetValue(_incomingAsset, assetBalance, _denominationAsset);\n\n        if (\n            !assetGavIsValid ||\n            assetGav.mul(ONE_HUNDRED_PERCENT).div(_totalGav) > _maxConcentration\n        ) {\n            return false;\n        }\n\n        return true;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the maxConcentration for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return maxConcentration_ The maxConcentration\n    function getMaxConcentrationForFund(address _comptrollerProxy)\n        external\n        view\n        returns (uint256 maxConcentration_)\n    {\n        return comptrollerProxyToMaxConcentration[_comptrollerProxy];\n    }\n\n    /// @notice Gets the `VALUE_INTERPRETER` variable\n    /// @return valueInterpreter_ The `VALUE_INTERPRETER` variable value\n    function getValueInterpreter() external view returns (address valueInterpreter_) {\n        return VALUE_INTERPRETER;\n    }\n}\n"
      },
      "contracts/release/core/fund/comptroller/ComptrollerLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport \"../../../../persistent/dispatcher/IDispatcher.sol\";\nimport \"../../../extensions/IExtension.sol\";\nimport \"../../../extensions/fee-manager/IFeeManager.sol\";\nimport \"../../../extensions/policy-manager/IPolicyManager.sol\";\nimport \"../../../infrastructure/price-feeds/primitives/IPrimitivePriceFeed.sol\";\nimport \"../../../infrastructure/value-interpreter/IValueInterpreter.sol\";\nimport \"../../../utils/AddressArrayLib.sol\";\nimport \"../../../utils/AssetFinalityResolver.sol\";\nimport \"../../fund-deployer/IFundDeployer.sol\";\nimport \"../vault/IVault.sol\";\nimport \"./IComptroller.sol\";\n\n/// @title ComptrollerLib Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice The core logic library shared by all funds\ncontract ComptrollerLib is IComptroller, AssetFinalityResolver {\n    using AddressArrayLib for address[];\n    using SafeMath for uint256;\n    using SafeERC20 for ERC20;\n\n    event MigratedSharesDuePaid(uint256 sharesDue);\n\n    event OverridePauseSet(bool indexed overridePause);\n\n    event PreRedeemSharesHookFailed(\n        bytes failureReturnData,\n        address redeemer,\n        uint256 sharesQuantity\n    );\n\n    event SharesBought(\n        address indexed caller,\n        address indexed buyer,\n        uint256 investmentAmount,\n        uint256 sharesIssued,\n        uint256 sharesReceived\n    );\n\n    event SharesRedeemed(\n        address indexed redeemer,\n        uint256 sharesQuantity,\n        address[] receivedAssets,\n        uint256[] receivedAssetQuantities\n    );\n\n    event VaultProxySet(address vaultProxy);\n\n    // Constants and immutables - shared by all proxies\n    uint256 private constant SHARES_UNIT = 10**18;\n    address private immutable DISPATCHER;\n    address private immutable FUND_DEPLOYER;\n    address private immutable FEE_MANAGER;\n    address private immutable INTEGRATION_MANAGER;\n    address private immutable PRIMITIVE_PRICE_FEED;\n    address private immutable POLICY_MANAGER;\n    address private immutable VALUE_INTERPRETER;\n\n    // Pseudo-constants (can only be set once)\n\n    address internal denominationAsset;\n    address internal vaultProxy;\n    // True only for the one non-proxy\n    bool internal isLib;\n\n    // Storage\n\n    // Allows a fund owner to override a release-level pause\n    bool internal overridePause;\n    // A reverse-mutex, granting atomic permission for particular contracts to make vault calls\n    bool internal permissionedVaultActionAllowed;\n    // A mutex to protect against reentrancy\n    bool internal reentranceLocked;\n    // A timelock between any \"shares actions\" (i.e., buy and redeem shares), per-account\n    uint256 internal sharesActionTimelock;\n    mapping(address => uint256) internal acctToLastSharesAction;\n\n    ///////////////\n    // MODIFIERS //\n    ///////////////\n\n    modifier allowsPermissionedVaultAction {\n        __assertPermissionedVaultActionNotAllowed();\n        permissionedVaultActionAllowed = true;\n        _;\n        permissionedVaultActionAllowed = false;\n    }\n\n    modifier locksReentrance() {\n        __assertNotReentranceLocked();\n        reentranceLocked = true;\n        _;\n        reentranceLocked = false;\n    }\n\n    modifier onlyActive() {\n        __assertIsActive(vaultProxy);\n        _;\n    }\n\n    modifier onlyNotPaused() {\n        __assertNotPaused();\n        _;\n    }\n\n    modifier onlyFundDeployer() {\n        __assertIsFundDeployer(msg.sender);\n        _;\n    }\n\n    modifier onlyOwner() {\n        __assertIsOwner(msg.sender);\n        _;\n    }\n\n    modifier timelockedSharesAction(address _account) {\n        __assertSharesActionNotTimelocked(_account);\n        _;\n        acctToLastSharesAction[_account] = block.timestamp;\n    }\n\n    // ASSERTION HELPERS\n\n    // Modifiers are inefficient in terms of contract size,\n    // so we use helper functions to prevent repetitive inlining of expensive string values.\n\n    /// @dev Since vaultProxy is set during activate(),\n    /// we can check that var rather than storing additional state\n    function __assertIsActive(address _vaultProxy) private pure {\n        require(_vaultProxy != address(0), \"Fund not active\");\n    }\n\n    function __assertIsFundDeployer(address _who) private view {\n        require(_who == FUND_DEPLOYER, \"Only FundDeployer callable\");\n    }\n\n    function __assertIsOwner(address _who) private view {\n        require(_who == IVault(vaultProxy).getOwner(), \"Only fund owner callable\");\n    }\n\n    function __assertLowLevelCall(bool _success, bytes memory _returnData) private pure {\n        require(_success, string(_returnData));\n    }\n\n    function __assertNotPaused() private view {\n        require(!__fundIsPaused(), \"Fund is paused\");\n    }\n\n    function __assertNotReentranceLocked() private view {\n        require(!reentranceLocked, \"Re-entrance\");\n    }\n\n    function __assertPermissionedVaultActionNotAllowed() private view {\n        require(!permissionedVaultActionAllowed, \"Vault action re-entrance\");\n    }\n\n    function __assertSharesActionNotTimelocked(address _account) private view {\n        require(\n            block.timestamp.sub(acctToLastSharesAction[_account]) >= sharesActionTimelock,\n            \"Shares action timelocked\"\n        );\n    }\n\n    constructor(\n        address _dispatcher,\n        address _fundDeployer,\n        address _valueInterpreter,\n        address _feeManager,\n        address _integrationManager,\n        address _policyManager,\n        address _primitivePriceFeed,\n        address _synthetixPriceFeed,\n        address _synthetixAddressResolver\n    ) public AssetFinalityResolver(_synthetixPriceFeed, _synthetixAddressResolver) {\n        DISPATCHER = _dispatcher;\n        FEE_MANAGER = _feeManager;\n        FUND_DEPLOYER = _fundDeployer;\n        INTEGRATION_MANAGER = _integrationManager;\n        PRIMITIVE_PRICE_FEED = _primitivePriceFeed;\n        POLICY_MANAGER = _policyManager;\n        VALUE_INTERPRETER = _valueInterpreter;\n        isLib = true;\n    }\n\n    /////////////\n    // GENERAL //\n    /////////////\n\n    /// @notice Calls a specified action on an Extension\n    /// @param _extension The Extension contract to call (e.g., FeeManager)\n    /// @param _actionId An ID representing the action to take on the extension (see extension)\n    /// @param _callArgs The encoded data for the call\n    /// @dev Used to route arbitrary calls, so that msg.sender is the ComptrollerProxy\n    /// (for access control). Uses a mutex of sorts that allows \"permissioned vault actions\"\n    /// during calls originating from this function.\n    function callOnExtension(\n        address _extension,\n        uint256 _actionId,\n        bytes calldata _callArgs\n    ) external override onlyNotPaused onlyActive locksReentrance allowsPermissionedVaultAction {\n        require(\n            _extension == FEE_MANAGER || _extension == INTEGRATION_MANAGER,\n            \"callOnExtension: _extension invalid\"\n        );\n\n        IExtension(_extension).receiveCallFromComptroller(msg.sender, _actionId, _callArgs);\n    }\n\n    /// @notice Sets or unsets an override on a release-wide pause\n    /// @param _nextOverridePause True if the pause should be overrode\n    function setOverridePause(bool _nextOverridePause) external onlyOwner {\n        require(_nextOverridePause != overridePause, \"setOverridePause: Value already set\");\n\n        overridePause = _nextOverridePause;\n\n        emit OverridePauseSet(_nextOverridePause);\n    }\n\n    /// @notice Makes an arbitrary call with the VaultProxy contract as the sender\n    /// @param _contract The contract to call\n    /// @param _selector The selector to call\n    /// @param _encodedArgs The encoded arguments for the call\n    function vaultCallOnContract(\n        address _contract,\n        bytes4 _selector,\n        bytes calldata _encodedArgs\n    ) external onlyNotPaused onlyActive onlyOwner {\n        require(\n            IFundDeployer(FUND_DEPLOYER).isRegisteredVaultCall(_contract, _selector),\n            \"vaultCallOnContract: Unregistered\"\n        );\n\n        IVault(vaultProxy).callOnContract(_contract, abi.encodePacked(_selector, _encodedArgs));\n    }\n\n    /// @dev Helper to check whether the release is paused, and that there is no local override\n    function __fundIsPaused() private view returns (bool) {\n        return\n            IFundDeployer(FUND_DEPLOYER).getReleaseStatus() ==\n            IFundDeployer.ReleaseStatus.Paused &&\n            !overridePause;\n    }\n\n    ////////////////////////////////\n    // PERMISSIONED VAULT ACTIONS //\n    ////////////////////////////////\n\n    /// @notice Makes a permissioned, state-changing call on the VaultProxy contract\n    /// @param _action The enum representing the VaultAction to perform on the VaultProxy\n    /// @param _actionData The call data for the action to perform\n    function permissionedVaultAction(VaultAction _action, bytes calldata _actionData)\n        external\n        override\n        onlyNotPaused\n        onlyActive\n    {\n        __assertPermissionedVaultAction(msg.sender, _action);\n\n        if (_action == VaultAction.AddTrackedAsset) {\n            __vaultActionAddTrackedAsset(_actionData);\n        } else if (_action == VaultAction.ApproveAssetSpender) {\n            __vaultActionApproveAssetSpender(_actionData);\n        } else if (_action == VaultAction.BurnShares) {\n            __vaultActionBurnShares(_actionData);\n        } else if (_action == VaultAction.MintShares) {\n            __vaultActionMintShares(_actionData);\n        } else if (_action == VaultAction.RemoveTrackedAsset) {\n            __vaultActionRemoveTrackedAsset(_actionData);\n        } else if (_action == VaultAction.TransferShares) {\n            __vaultActionTransferShares(_actionData);\n        } else if (_action == VaultAction.WithdrawAssetTo) {\n            __vaultActionWithdrawAssetTo(_actionData);\n        }\n    }\n\n    /// @dev Helper to assert that a caller is allowed to perform a particular VaultAction\n    function __assertPermissionedVaultAction(address _caller, VaultAction _action) private view {\n        require(\n            permissionedVaultActionAllowed,\n            \"__assertPermissionedVaultAction: No action allowed\"\n        );\n\n        if (_caller == INTEGRATION_MANAGER) {\n            require(\n                _action == VaultAction.ApproveAssetSpender ||\n                    _action == VaultAction.AddTrackedAsset ||\n                    _action == VaultAction.RemoveTrackedAsset ||\n                    _action == VaultAction.WithdrawAssetTo,\n                \"__assertPermissionedVaultAction: Not valid for IntegrationManager\"\n            );\n        } else if (_caller == FEE_MANAGER) {\n            require(\n                _action == VaultAction.BurnShares ||\n                    _action == VaultAction.MintShares ||\n                    _action == VaultAction.TransferShares,\n                \"__assertPermissionedVaultAction: Not valid for FeeManager\"\n            );\n        } else {\n            revert(\"__assertPermissionedVaultAction: Not a valid actor\");\n        }\n    }\n\n    /// @dev Helper to add a tracked asset to the fund\n    function __vaultActionAddTrackedAsset(bytes memory _actionData) private {\n        address asset = abi.decode(_actionData, (address));\n        IVault(vaultProxy).addTrackedAsset(asset);\n    }\n\n    /// @dev Helper to grant a spender an allowance for a fund's asset\n    function __vaultActionApproveAssetSpender(bytes memory _actionData) private {\n        (address asset, address target, uint256 amount) = abi.decode(\n            _actionData,\n            (address, address, uint256)\n        );\n        IVault(vaultProxy).approveAssetSpender(asset, target, amount);\n    }\n\n    /// @dev Helper to burn fund shares for a particular account\n    function __vaultActionBurnShares(bytes memory _actionData) private {\n        (address target, uint256 amount) = abi.decode(_actionData, (address, uint256));\n        IVault(vaultProxy).burnShares(target, amount);\n    }\n\n    /// @dev Helper to mint fund shares to a particular account\n    function __vaultActionMintShares(bytes memory _actionData) private {\n        (address target, uint256 amount) = abi.decode(_actionData, (address, uint256));\n        IVault(vaultProxy).mintShares(target, amount);\n    }\n\n    /// @dev Helper to remove a tracked asset from the fund\n    function __vaultActionRemoveTrackedAsset(bytes memory _actionData) private {\n        address asset = abi.decode(_actionData, (address));\n\n        // Allowing this to fail silently makes it cheaper and simpler\n        // for Extensions to not query for the denomination asset\n        if (asset != denominationAsset) {\n            IVault(vaultProxy).removeTrackedAsset(asset);\n        }\n    }\n\n    /// @dev Helper to transfer fund shares from one account to another\n    function __vaultActionTransferShares(bytes memory _actionData) private {\n        (address from, address to, uint256 amount) = abi.decode(\n            _actionData,\n            (address, address, uint256)\n        );\n        IVault(vaultProxy).transferShares(from, to, amount);\n    }\n\n    /// @dev Helper to withdraw an asset from the VaultProxy to a given account\n    function __vaultActionWithdrawAssetTo(bytes memory _actionData) private {\n        (address asset, address target, uint256 amount) = abi.decode(\n            _actionData,\n            (address, address, uint256)\n        );\n        IVault(vaultProxy).withdrawAssetTo(asset, target, amount);\n    }\n\n    ///////////////\n    // LIFECYCLE //\n    ///////////////\n\n    /// @notice Initializes a fund with its core config\n    /// @param _denominationAsset The asset in which the fund's value should be denominated\n    /// @param _sharesActionTimelock The minimum number of seconds between any two \"shares actions\"\n    /// (buying or selling shares) by the same user\n    /// @dev Pseudo-constructor per proxy.\n    /// No need to assert access because this is called atomically on deployment,\n    /// and once it's called, it cannot be called again.\n    function init(address _denominationAsset, uint256 _sharesActionTimelock) external override {\n        require(denominationAsset == address(0), \"init: Already initialized\");\n        require(\n            IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_denominationAsset),\n            \"init: Bad denomination asset\"\n        );\n\n        denominationAsset = _denominationAsset;\n        sharesActionTimelock = _sharesActionTimelock;\n    }\n\n    /// @notice Configure the extensions of a fund\n    /// @param _feeManagerConfigData Encoded config for fees to enable\n    /// @param _policyManagerConfigData Encoded config for policies to enable\n    /// @dev No need to assert anything beyond FundDeployer access.\n    /// Called atomically with init(), but after ComptrollerLib has been deployed,\n    /// giving access to its state and interface\n    function configureExtensions(\n        bytes calldata _feeManagerConfigData,\n        bytes calldata _policyManagerConfigData\n    ) external override onlyFundDeployer {\n        if (_feeManagerConfigData.length > 0) {\n            IExtension(FEE_MANAGER).setConfigForFund(_feeManagerConfigData);\n        }\n        if (_policyManagerConfigData.length > 0) {\n            IExtension(POLICY_MANAGER).setConfigForFund(_policyManagerConfigData);\n        }\n    }\n\n    /// @notice Activates the fund by attaching a VaultProxy and activating all Extensions\n    /// @param _vaultProxy The VaultProxy to attach to the fund\n    /// @param _isMigration True if a migrated fund is being activated\n    /// @dev No need to assert anything beyond FundDeployer access.\n    function activate(address _vaultProxy, bool _isMigration) external override onlyFundDeployer {\n        vaultProxy = _vaultProxy;\n\n        emit VaultProxySet(_vaultProxy);\n\n        if (_isMigration) {\n            // Distribute any shares in the VaultProxy to the fund owner.\n            // This is a mechanism to ensure that even in the edge case of a fund being unable\n            // to payout fee shares owed during migration, these shares are not lost.\n            uint256 sharesDue = ERC20(_vaultProxy).balanceOf(_vaultProxy);\n            if (sharesDue > 0) {\n                IVault(_vaultProxy).transferShares(\n                    _vaultProxy,\n                    IVault(_vaultProxy).getOwner(),\n                    sharesDue\n                );\n\n                emit MigratedSharesDuePaid(sharesDue);\n            }\n        }\n\n        // Note: a future release could consider forcing the adding of a tracked asset here,\n        // just in case a fund is migrating from an old configuration where they are not able\n        // to remove an asset to get under the tracked assets limit\n        IVault(_vaultProxy).addTrackedAsset(denominationAsset);\n\n        // Activate extensions\n        IExtension(FEE_MANAGER).activateForFund(_isMigration);\n        IExtension(INTEGRATION_MANAGER).activateForFund(_isMigration);\n        IExtension(POLICY_MANAGER).activateForFund(_isMigration);\n    }\n\n    /// @notice Remove the config for a fund\n    /// @dev No need to assert anything beyond FundDeployer access.\n    /// Calling onlyNotPaused here rather than in the FundDeployer allows\n    /// the owner to potentially override the pause and rescue unpaid fees.\n    function destruct()\n        external\n        override\n        onlyFundDeployer\n        onlyNotPaused\n        allowsPermissionedVaultAction\n    {\n        // Failsafe to protect the libs against selfdestruct\n        require(!isLib, \"destruct: Only delegate callable\");\n\n        // Deactivate the extensions\n        IExtension(FEE_MANAGER).deactivateForFund();\n        IExtension(INTEGRATION_MANAGER).deactivateForFund();\n        IExtension(POLICY_MANAGER).deactivateForFund();\n\n        // Delete storage of ComptrollerProxy\n        // There should never be ETH in the ComptrollerLib, so no need to waste gas\n        // to get the fund owner\n        selfdestruct(address(0));\n    }\n\n    ////////////////\n    // ACCOUNTING //\n    ////////////////\n\n    /// @notice Calculates the gross asset value (GAV) of the fund\n    /// @param _requireFinality True if all assets must have exact final balances settled\n    /// @return gav_ The fund GAV\n    /// @return isValid_ True if the conversion rates used to derive the GAV are all valid\n    function calcGav(bool _requireFinality) public override returns (uint256 gav_, bool isValid_) {\n        address vaultProxyAddress = vaultProxy;\n        address[] memory assets = IVault(vaultProxyAddress).getTrackedAssets();\n        if (assets.length == 0) {\n            return (0, true);\n        }\n\n        uint256[] memory balances = new uint256[](assets.length);\n        for (uint256 i; i < assets.length; i++) {\n            balances[i] = __finalizeIfSynthAndGetAssetBalance(\n                vaultProxyAddress,\n                assets[i],\n                _requireFinality\n            );\n        }\n\n        (gav_, isValid_) = IValueInterpreter(VALUE_INTERPRETER).calcCanonicalAssetsTotalValue(\n            assets,\n            balances,\n            denominationAsset\n        );\n\n        return (gav_, isValid_);\n    }\n\n    /// @notice Calculates the gross value of 1 unit of shares in the fund's denomination asset\n    /// @param _requireFinality True if all assets must have exact final balances settled\n    /// @return grossShareValue_ The amount of the denomination asset per share\n    /// @return isValid_ True if the conversion rates to derive the value are all valid\n    /// @dev Does not account for any fees outstanding.\n    function calcGrossShareValue(bool _requireFinality)\n        external\n        override\n        returns (uint256 grossShareValue_, bool isValid_)\n    {\n        uint256 gav;\n        (gav, isValid_) = calcGav(_requireFinality);\n\n        grossShareValue_ = __calcGrossShareValue(\n            gav,\n            ERC20(vaultProxy).totalSupply(),\n            10**uint256(ERC20(denominationAsset).decimals())\n        );\n\n        return (grossShareValue_, isValid_);\n    }\n\n    /// @dev Helper for calculating the gross share value\n    function __calcGrossShareValue(\n        uint256 _gav,\n        uint256 _sharesSupply,\n        uint256 _denominationAssetUnit\n    ) private pure returns (uint256 grossShareValue_) {\n        if (_sharesSupply == 0) {\n            return _denominationAssetUnit;\n        }\n\n        return _gav.mul(SHARES_UNIT).div(_sharesSupply);\n    }\n\n    ///////////////////\n    // PARTICIPATION //\n    ///////////////////\n\n    // BUY SHARES\n\n    /// @notice Buys shares in the fund for multiple sets of criteria\n    /// @param _buyers The accounts for which to buy shares\n    /// @param _investmentAmounts The amounts of the fund's denomination asset\n    /// with which to buy shares for the corresponding _buyers\n    /// @param _minSharesQuantities The minimum quantities of shares to buy\n    /// with the corresponding _investmentAmounts\n    /// @return sharesReceivedAmounts_ The actual amounts of shares received\n    /// by the corresponding _buyers\n    /// @dev Param arrays have indexes corresponding to individual __buyShares() orders.\n    function buyShares(\n        address[] calldata _buyers,\n        uint256[] calldata _investmentAmounts,\n        uint256[] calldata _minSharesQuantities\n    )\n        external\n        onlyNotPaused\n        locksReentrance\n        allowsPermissionedVaultAction\n        returns (uint256[] memory sharesReceivedAmounts_)\n    {\n        require(_buyers.length > 0, \"buyShares: Empty _buyers\");\n        require(\n            _buyers.length == _investmentAmounts.length &&\n                _buyers.length == _minSharesQuantities.length,\n            \"buyShares: Unequal arrays\"\n        );\n\n        address vaultProxyCopy = vaultProxy;\n        __assertIsActive(vaultProxyCopy);\n        require(\n            !IDispatcher(DISPATCHER).hasMigrationRequest(vaultProxyCopy),\n            \"buyShares: Pending migration\"\n        );\n\n        (uint256 gav, bool gavIsValid) = calcGav(true);\n        require(gavIsValid, \"buyShares: Invalid GAV\");\n\n        __buySharesSetupHook(msg.sender, _investmentAmounts, gav);\n\n        address denominationAssetCopy = denominationAsset;\n        uint256 sharePrice = __calcGrossShareValue(\n            gav,\n            ERC20(vaultProxyCopy).totalSupply(),\n            10**uint256(ERC20(denominationAssetCopy).decimals())\n        );\n\n        sharesReceivedAmounts_ = new uint256[](_buyers.length);\n        for (uint256 i; i < _buyers.length; i++) {\n            sharesReceivedAmounts_[i] = __buyShares(\n                _buyers[i],\n                _investmentAmounts[i],\n                _minSharesQuantities[i],\n                vaultProxyCopy,\n                sharePrice,\n                gav,\n                denominationAssetCopy\n            );\n\n            gav = gav.add(_investmentAmounts[i]);\n        }\n\n        __buySharesCompletedHook(msg.sender, sharesReceivedAmounts_, gav);\n\n        return sharesReceivedAmounts_;\n    }\n\n    /// @dev Helper to buy shares\n    function __buyShares(\n        address _buyer,\n        uint256 _investmentAmount,\n        uint256 _minSharesQuantity,\n        address _vaultProxy,\n        uint256 _sharePrice,\n        uint256 _preBuySharesGav,\n        address _denominationAsset\n    ) private timelockedSharesAction(_buyer) returns (uint256 sharesReceived_) {\n        require(_investmentAmount > 0, \"__buyShares: Empty _investmentAmount\");\n\n        // Gives Extensions a chance to run logic prior to the minting of bought shares\n        __preBuySharesHook(_buyer, _investmentAmount, _minSharesQuantity, _preBuySharesGav);\n\n        // Calculate the amount of shares to issue with the investment amount\n        uint256 sharesIssued = _investmentAmount.mul(SHARES_UNIT).div(_sharePrice);\n\n        // Mint shares to the buyer\n        uint256 prevBuyerShares = ERC20(_vaultProxy).balanceOf(_buyer);\n        IVault(_vaultProxy).mintShares(_buyer, sharesIssued);\n\n        // Transfer the investment asset to the fund.\n        // Does not follow the checks-effects-interactions pattern, but it is preferred\n        // to have the final state of the VaultProxy prior to running __postBuySharesHook().\n        ERC20(_denominationAsset).safeTransferFrom(msg.sender, _vaultProxy, _investmentAmount);\n\n        // Gives Extensions a chance to run logic after shares are issued\n        __postBuySharesHook(_buyer, _investmentAmount, sharesIssued, _preBuySharesGav);\n\n        // The number of actual shares received may differ from shares issued due to\n        // how the PostBuyShares hooks are invoked by Extensions (i.e., fees)\n        sharesReceived_ = ERC20(_vaultProxy).balanceOf(_buyer).sub(prevBuyerShares);\n        require(\n            sharesReceived_ >= _minSharesQuantity,\n            \"__buyShares: Shares received < _minSharesQuantity\"\n        );\n\n        emit SharesBought(msg.sender, _buyer, _investmentAmount, sharesIssued, sharesReceived_);\n\n        return sharesReceived_;\n    }\n\n    /// @dev Helper for Extension actions after all __buyShares() calls are made\n    function __buySharesCompletedHook(\n        address _caller,\n        uint256[] memory _sharesReceivedAmounts,\n        uint256 _gav\n    ) private {\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            address(this),\n            IPolicyManager.PolicyHook.BuySharesCompleted,\n            abi.encode(_caller, _sharesReceivedAmounts, _gav)\n        );\n\n        IFeeManager(FEE_MANAGER).invokeHook(\n            IFeeManager.FeeHook.BuySharesCompleted,\n            abi.encode(_caller, _sharesReceivedAmounts),\n            _gav\n        );\n    }\n\n    /// @dev Helper for Extension actions before any __buyShares() calls are made\n    function __buySharesSetupHook(\n        address _caller,\n        uint256[] memory _investmentAmounts,\n        uint256 _gav\n    ) private {\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            address(this),\n            IPolicyManager.PolicyHook.BuySharesSetup,\n            abi.encode(_caller, _investmentAmounts, _gav)\n        );\n\n        IFeeManager(FEE_MANAGER).invokeHook(\n            IFeeManager.FeeHook.BuySharesSetup,\n            abi.encode(_caller, _investmentAmounts),\n            _gav\n        );\n    }\n\n    /// @dev Helper for Extension actions immediately prior to issuing shares.\n    /// This could be cleaned up so both Extensions take the same encoded args and handle GAV\n    /// in the same way, but there is not the obvious need for gas savings of recycling\n    /// the GAV value for the current policies as there is for the fees.\n    function __preBuySharesHook(\n        address _buyer,\n        uint256 _investmentAmount,\n        uint256 _minSharesQuantity,\n        uint256 _gav\n    ) private {\n        IFeeManager(FEE_MANAGER).invokeHook(\n            IFeeManager.FeeHook.PreBuyShares,\n            abi.encode(_buyer, _investmentAmount, _minSharesQuantity),\n            _gav\n        );\n\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            address(this),\n            IPolicyManager.PolicyHook.PreBuyShares,\n            abi.encode(_buyer, _investmentAmount, _minSharesQuantity, _gav)\n        );\n    }\n\n    /// @dev Helper for Extension actions immediately after issuing shares.\n    /// Same comment applies from __preBuySharesHook() above.\n    function __postBuySharesHook(\n        address _buyer,\n        uint256 _investmentAmount,\n        uint256 _sharesIssued,\n        uint256 _preBuySharesGav\n    ) private {\n        uint256 gav = _preBuySharesGav.add(_investmentAmount);\n        IFeeManager(FEE_MANAGER).invokeHook(\n            IFeeManager.FeeHook.PostBuyShares,\n            abi.encode(_buyer, _investmentAmount, _sharesIssued),\n            gav\n        );\n\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            address(this),\n            IPolicyManager.PolicyHook.PostBuyShares,\n            abi.encode(_buyer, _investmentAmount, _sharesIssued, gav)\n        );\n    }\n\n    // REDEEM SHARES\n\n    /// @notice Redeem all of the sender's shares for a proportionate slice of the fund's assets\n    /// @return payoutAssets_ The assets paid out to the redeemer\n    /// @return payoutAmounts_ The amount of each asset paid out to the redeemer\n    /// @dev See __redeemShares() for further detail\n    function redeemShares()\n        external\n        returns (address[] memory payoutAssets_, uint256[] memory payoutAmounts_)\n    {\n        return\n            __redeemShares(\n                msg.sender,\n                ERC20(vaultProxy).balanceOf(msg.sender),\n                new address[](0),\n                new address[](0)\n            );\n    }\n\n    /// @notice Redeem a specified quantity of the sender's shares for a proportionate slice of\n    /// the fund's assets, optionally specifying additional assets and assets to skip.\n    /// @param _sharesQuantity The quantity of shares to redeem\n    /// @param _additionalAssets Additional (non-tracked) assets to claim\n    /// @param _assetsToSkip Tracked assets to forfeit\n    /// @return payoutAssets_ The assets paid out to the redeemer\n    /// @return payoutAmounts_ The amount of each asset paid out to the redeemer\n    /// @dev Any claim to passed _assetsToSkip will be forfeited entirely. This should generally\n    /// only be exercised if a bad asset is causing redemption to fail.\n    function redeemSharesDetailed(\n        uint256 _sharesQuantity,\n        address[] calldata _additionalAssets,\n        address[] calldata _assetsToSkip\n    ) external returns (address[] memory payoutAssets_, uint256[] memory payoutAmounts_) {\n        return __redeemShares(msg.sender, _sharesQuantity, _additionalAssets, _assetsToSkip);\n    }\n\n    /// @dev Helper to parse an array of payout assets during redemption, taking into account\n    /// additional assets and assets to skip. _assetsToSkip ignores _additionalAssets.\n    /// All input arrays are assumed to be unique.\n    function __parseRedemptionPayoutAssets(\n        address[] memory _trackedAssets,\n        address[] memory _additionalAssets,\n        address[] memory _assetsToSkip\n    ) private pure returns (address[] memory payoutAssets_) {\n        address[] memory trackedAssetsToPayout = _trackedAssets.removeItems(_assetsToSkip);\n        if (_additionalAssets.length == 0) {\n            return trackedAssetsToPayout;\n        }\n\n        // Add additional assets. Duplicates of trackedAssets are ignored.\n        bool[] memory indexesToAdd = new bool[](_additionalAssets.length);\n        uint256 additionalItemsCount;\n        for (uint256 i; i < _additionalAssets.length; i++) {\n            if (!trackedAssetsToPayout.contains(_additionalAssets[i])) {\n                indexesToAdd[i] = true;\n                additionalItemsCount++;\n            }\n        }\n        if (additionalItemsCount == 0) {\n            return trackedAssetsToPayout;\n        }\n\n        payoutAssets_ = new address[](trackedAssetsToPayout.length.add(additionalItemsCount));\n        for (uint256 i; i < trackedAssetsToPayout.length; i++) {\n            payoutAssets_[i] = trackedAssetsToPayout[i];\n        }\n        uint256 payoutAssetsIndex = trackedAssetsToPayout.length;\n        for (uint256 i; i < _additionalAssets.length; i++) {\n            if (indexesToAdd[i]) {\n                payoutAssets_[payoutAssetsIndex] = _additionalAssets[i];\n                payoutAssetsIndex++;\n            }\n        }\n\n        return payoutAssets_;\n    }\n\n    /// @dev Helper for system actions immediately prior to redeeming shares.\n    /// Policy validation is not currently allowed on redemption, to ensure continuous redeemability.\n    function __preRedeemSharesHook(address _redeemer, uint256 _sharesQuantity)\n        private\n        allowsPermissionedVaultAction\n    {\n        try\n            IFeeManager(FEE_MANAGER).invokeHook(\n                IFeeManager.FeeHook.PreRedeemShares,\n                abi.encode(_redeemer, _sharesQuantity),\n                0\n            )\n         {} catch (bytes memory reason) {\n            emit PreRedeemSharesHookFailed(reason, _redeemer, _sharesQuantity);\n        }\n    }\n\n    /// @dev Helper to redeem shares.\n    /// This function should never fail without a way to bypass the failure, which is assured\n    /// through two mechanisms:\n    /// 1. The FeeManager is called with the try/catch pattern to assure that calls to it\n    /// can never block redemption.\n    /// 2. If a token fails upon transfer(), that token can be skipped (and its balance forfeited)\n    /// by explicitly specifying _assetsToSkip.\n    /// Because of these assurances, shares should always be redeemable, with the exception\n    /// of the timelock period on shares actions that must be respected.\n    function __redeemShares(\n        address _redeemer,\n        uint256 _sharesQuantity,\n        address[] memory _additionalAssets,\n        address[] memory _assetsToSkip\n    )\n        private\n        locksReentrance\n        returns (address[] memory payoutAssets_, uint256[] memory payoutAmounts_)\n    {\n        require(_sharesQuantity > 0, \"__redeemShares: _sharesQuantity must be >0\");\n        require(\n            _additionalAssets.isUniqueSet(),\n            \"__redeemShares: _additionalAssets contains duplicates\"\n        );\n        require(_assetsToSkip.isUniqueSet(), \"__redeemShares: _assetsToSkip contains duplicates\");\n\n        IVault vaultProxyContract = IVault(vaultProxy);\n\n        // Only apply the sharesActionTimelock when a migration is not pending\n        if (!IDispatcher(DISPATCHER).hasMigrationRequest(address(vaultProxyContract))) {\n            __assertSharesActionNotTimelocked(_redeemer);\n            acctToLastSharesAction[_redeemer] = block.timestamp;\n        }\n\n        // When a fund is paused, settling fees will be skipped\n        if (!__fundIsPaused()) {\n            // Note that if a fee with `SettlementType.Direct` is charged here (i.e., not `Mint`),\n            // then those fee shares will be transferred from the user's balance rather\n            // than reallocated from the sharesQuantity being redeemed.\n            __preRedeemSharesHook(_redeemer, _sharesQuantity);\n        }\n\n        // Check the shares quantity against the user's balance after settling fees\n        ERC20 sharesContract = ERC20(address(vaultProxyContract));\n        require(\n            _sharesQuantity <= sharesContract.balanceOf(_redeemer),\n            \"__redeemShares: Insufficient shares\"\n        );\n\n        // Parse the payout assets given optional params to add or skip assets.\n        // Note that there is no validation that the _additionalAssets are known assets to\n        // the protocol. This means that the redeemer could specify a malicious asset,\n        // but since all state-changing, user-callable functions on this contract share the\n        // non-reentrant modifier, there is nowhere to perform a reentrancy attack.\n        payoutAssets_ = __parseRedemptionPayoutAssets(\n            vaultProxyContract.getTrackedAssets(),\n            _additionalAssets,\n            _assetsToSkip\n        );\n        require(payoutAssets_.length > 0, \"__redeemShares: No payout assets\");\n\n        // Destroy the shares.\n        // Must get the shares supply before doing so.\n        uint256 sharesSupply = sharesContract.totalSupply();\n        vaultProxyContract.burnShares(_redeemer, _sharesQuantity);\n\n        // Calculate and transfer payout asset amounts due to redeemer\n        payoutAmounts_ = new uint256[](payoutAssets_.length);\n        address denominationAssetCopy = denominationAsset;\n        for (uint256 i; i < payoutAssets_.length; i++) {\n            uint256 assetBalance = __finalizeIfSynthAndGetAssetBalance(\n                address(vaultProxyContract),\n                payoutAssets_[i],\n                true\n            );\n\n            // If all remaining shares are being redeemed, the logic changes slightly\n            if (_sharesQuantity == sharesSupply) {\n                payoutAmounts_[i] = assetBalance;\n                // Remove every tracked asset, except the denomination asset\n                if (payoutAssets_[i] != denominationAssetCopy) {\n                    vaultProxyContract.removeTrackedAsset(payoutAssets_[i]);\n                }\n            } else {\n                payoutAmounts_[i] = assetBalance.mul(_sharesQuantity).div(sharesSupply);\n            }\n\n            // Transfer payout asset to redeemer\n            if (payoutAmounts_[i] > 0) {\n                vaultProxyContract.withdrawAssetTo(payoutAssets_[i], _redeemer, payoutAmounts_[i]);\n            }\n        }\n\n        emit SharesRedeemed(_redeemer, _sharesQuantity, payoutAssets_, payoutAmounts_);\n\n        return (payoutAssets_, payoutAmounts_);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `denominationAsset` variable\n    /// @return denominationAsset_ The `denominationAsset` variable value\n    function getDenominationAsset() external view override returns (address denominationAsset_) {\n        return denominationAsset;\n    }\n\n    /// @notice Gets the routes for the various contracts used by all funds\n    /// @return dispatcher_ The `DISPATCHER` variable value\n    /// @return feeManager_ The `FEE_MANAGER` variable value\n    /// @return fundDeployer_ The `FUND_DEPLOYER` variable value\n    /// @return integrationManager_ The `INTEGRATION_MANAGER` variable value\n    /// @return policyManager_ The `POLICY_MANAGER` variable value\n    /// @return primitivePriceFeed_ The `PRIMITIVE_PRICE_FEED` variable value\n    /// @return valueInterpreter_ The `VALUE_INTERPRETER` variable value\n    function getLibRoutes()\n        external\n        view\n        returns (\n            address dispatcher_,\n            address feeManager_,\n            address fundDeployer_,\n            address integrationManager_,\n            address policyManager_,\n            address primitivePriceFeed_,\n            address valueInterpreter_\n        )\n    {\n        return (\n            DISPATCHER,\n            FEE_MANAGER,\n            FUND_DEPLOYER,\n            INTEGRATION_MANAGER,\n            POLICY_MANAGER,\n            PRIMITIVE_PRICE_FEED,\n            VALUE_INTERPRETER\n        );\n    }\n\n    /// @notice Gets the `overridePause` variable\n    /// @return overridePause_ The `overridePause` variable value\n    function getOverridePause() external view returns (bool overridePause_) {\n        return overridePause;\n    }\n\n    /// @notice Gets the `sharesActionTimelock` variable\n    /// @return sharesActionTimelock_ The `sharesActionTimelock` variable value\n    function getSharesActionTimelock() external view returns (uint256 sharesActionTimelock_) {\n        return sharesActionTimelock;\n    }\n\n    /// @notice Gets the `vaultProxy` variable\n    /// @return vaultProxy_ The `vaultProxy` variable value\n    function getVaultProxy() external view override returns (address vaultProxy_) {\n        return vaultProxy;\n    }\n}\n"
      },
      "contracts/release/core/fund/vault/VaultLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport \"../../../../persistent/dispatcher/IDispatcher.sol\";\nimport \"../../../../persistent/vault/VaultLibBase1.sol\";\nimport \"./IVault.sol\";\n\n/// @title VaultLib Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice The per-release proxiable library contract for VaultProxy\n/// @dev The difference in terminology between \"asset\" and \"trackedAsset\" is intentional.\n/// A fund might actually have asset balances of un-tracked assets,\n/// but only tracked assets are used in gav calculations.\n/// Note that this contract inherits VaultLibSafeMath (a verbatim Open Zeppelin SafeMath copy)\n/// from SharesTokenBase via VaultLibBase1\ncontract VaultLib is VaultLibBase1, IVault {\n    using SafeERC20 for ERC20;\n\n    // Before updating TRACKED_ASSETS_LIMIT in the future, it is important to consider:\n    // 1. The highest tracked assets limit ever allowed in the protocol\n    // 2. That the next value will need to be respected by all future releases\n    uint256 private constant TRACKED_ASSETS_LIMIT = 20;\n\n    modifier onlyAccessor() {\n        require(msg.sender == accessor, \"Only the designated accessor can make this call\");\n        _;\n    }\n\n    /////////////\n    // GENERAL //\n    /////////////\n\n    /// @notice Sets the account that is allowed to migrate a fund to new releases\n    /// @param _nextMigrator The account to set as the allowed migrator\n    /// @dev Set to address(0) to remove the migrator.\n    function setMigrator(address _nextMigrator) external {\n        require(msg.sender == owner, \"setMigrator: Only the owner can call this function\");\n        address prevMigrator = migrator;\n        require(_nextMigrator != prevMigrator, \"setMigrator: Value already set\");\n\n        migrator = _nextMigrator;\n\n        emit MigratorSet(prevMigrator, _nextMigrator);\n    }\n\n    ///////////\n    // VAULT //\n    ///////////\n\n    /// @notice Adds a tracked asset to the fund\n    /// @param _asset The asset to add\n    /// @dev Allows addition of already tracked assets to fail silently.\n    function addTrackedAsset(address _asset) external override onlyAccessor {\n        if (!isTrackedAsset(_asset)) {\n            require(\n                trackedAssets.length < TRACKED_ASSETS_LIMIT,\n                \"addTrackedAsset: Limit exceeded\"\n            );\n\n            assetToIsTracked[_asset] = true;\n            trackedAssets.push(_asset);\n\n            emit TrackedAssetAdded(_asset);\n        }\n    }\n\n    /// @notice Grants an allowance to a spender to use the fund's asset\n    /// @param _asset The asset for which to grant an allowance\n    /// @param _target The spender of the allowance\n    /// @param _amount The amount of the allowance\n    function approveAssetSpender(\n        address _asset,\n        address _target,\n        uint256 _amount\n    ) external override onlyAccessor {\n        ERC20(_asset).approve(_target, _amount);\n    }\n\n    /// @notice Makes an arbitrary call with this contract as the sender\n    /// @param _contract The contract to call\n    /// @param _callData The call data for the call\n    function callOnContract(address _contract, bytes calldata _callData)\n        external\n        override\n        onlyAccessor\n    {\n        (bool success, bytes memory returnData) = _contract.call(_callData);\n        require(success, string(returnData));\n    }\n\n    /// @notice Removes a tracked asset from the fund\n    /// @param _asset The asset to remove\n    function removeTrackedAsset(address _asset) external override onlyAccessor {\n        __removeTrackedAsset(_asset);\n    }\n\n    /// @notice Withdraws an asset from the VaultProxy to a given account\n    /// @param _asset The asset to withdraw\n    /// @param _target The account to which to withdraw the asset\n    /// @param _amount The amount of asset to withdraw\n    function withdrawAssetTo(\n        address _asset,\n        address _target,\n        uint256 _amount\n    ) external override onlyAccessor {\n        ERC20(_asset).safeTransfer(_target, _amount);\n\n        emit AssetWithdrawn(_asset, _target, _amount);\n    }\n\n    /// @dev Helper to the get the Vault's balance of a given asset\n    function __getAssetBalance(address _asset) private view returns (uint256 balance_) {\n        return ERC20(_asset).balanceOf(address(this));\n    }\n\n    /// @dev Helper to remove an asset from a fund's tracked assets.\n    /// Allows removal of non-tracked asset to fail silently.\n    function __removeTrackedAsset(address _asset) private {\n        if (isTrackedAsset(_asset)) {\n            assetToIsTracked[_asset] = false;\n\n            uint256 trackedAssetsCount = trackedAssets.length;\n            for (uint256 i = 0; i < trackedAssetsCount; i++) {\n                if (trackedAssets[i] == _asset) {\n                    if (i < trackedAssetsCount - 1) {\n                        trackedAssets[i] = trackedAssets[trackedAssetsCount - 1];\n                    }\n                    trackedAssets.pop();\n                    break;\n                }\n            }\n\n            emit TrackedAssetRemoved(_asset);\n        }\n    }\n\n    ////////////\n    // SHARES //\n    ////////////\n\n    /// @notice Burns fund shares from a particular account\n    /// @param _target The account for which to burn shares\n    /// @param _amount The amount of shares to burn\n    function burnShares(address _target, uint256 _amount) external override onlyAccessor {\n        __burn(_target, _amount);\n    }\n\n    /// @notice Mints fund shares to a particular account\n    /// @param _target The account for which to burn shares\n    /// @param _amount The amount of shares to mint\n    function mintShares(address _target, uint256 _amount) external override onlyAccessor {\n        __mint(_target, _amount);\n    }\n\n    /// @notice Transfers fund shares from one account to another\n    /// @param _from The account from which to transfer shares\n    /// @param _to The account to which to transfer shares\n    /// @param _amount The amount of shares to transfer\n    function transferShares(\n        address _from,\n        address _to,\n        uint256 _amount\n    ) external override onlyAccessor {\n        __transfer(_from, _to, _amount);\n    }\n\n    // ERC20 overrides\n\n    /// @dev Disallows the standard ERC20 approve() function\n    function approve(address, uint256) public override returns (bool) {\n        revert(\"Unimplemented\");\n    }\n\n    /// @notice Gets the `symbol` value of the shares token\n    /// @return symbol_ The `symbol` value\n    /// @dev Defers the shares symbol value to the Dispatcher contract\n    function symbol() public view override returns (string memory symbol_) {\n        return IDispatcher(creator).getSharesTokenSymbol();\n    }\n\n    /// @dev Disallows the standard ERC20 transfer() function\n    function transfer(address, uint256) public override returns (bool) {\n        revert(\"Unimplemented\");\n    }\n\n    /// @dev Disallows the standard ERC20 transferFrom() function\n    function transferFrom(\n        address,\n        address,\n        uint256\n    ) public override returns (bool) {\n        revert(\"Unimplemented\");\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `accessor` variable\n    /// @return accessor_ The `accessor` variable value\n    function getAccessor() external view override returns (address accessor_) {\n        return accessor;\n    }\n\n    /// @notice Gets the `creator` variable\n    /// @return creator_ The `creator` variable value\n    function getCreator() external view returns (address creator_) {\n        return creator;\n    }\n\n    /// @notice Gets the `migrator` variable\n    /// @return migrator_ The `migrator` variable value\n    function getMigrator() external view returns (address migrator_) {\n        return migrator;\n    }\n\n    /// @notice Gets the `owner` variable\n    /// @return owner_ The `owner` variable value\n    function getOwner() external view override returns (address owner_) {\n        return owner;\n    }\n\n    /// @notice Gets the `trackedAssets` variable\n    /// @return trackedAssets_ The `trackedAssets` variable value\n    function getTrackedAssets() external view override returns (address[] memory trackedAssets_) {\n        return trackedAssets;\n    }\n\n    /// @notice Check whether an address is a tracked asset of the fund\n    /// @param _asset The address to check\n    /// @return isTrackedAsset_ True if the address is a tracked asset of the fund\n    function isTrackedAsset(address _asset) public view override returns (bool isTrackedAsset_) {\n        return assetToIsTracked[_asset];\n    }\n}\n"
      },
      "contracts/release/infrastructure/value-interpreter/ValueInterpreter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../price-feeds/derivatives/IAggregatedDerivativePriceFeed.sol\";\nimport \"../price-feeds/derivatives/IDerivativePriceFeed.sol\";\nimport \"../price-feeds/primitives/IPrimitivePriceFeed.sol\";\nimport \"./IValueInterpreter.sol\";\n\n/// @title ValueInterpreter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interprets price feeds to provide covert value between asset pairs\n/// @dev This contract contains several \"live\" value calculations, which for this release are simply\n/// aliases to their \"canonical\" value counterparts since the only primitive price feed (Chainlink)\n/// is immutable in this contract and only has one type of value. Including the \"live\" versions of\n/// functions only serves as a placeholder for infrastructural components and plugins (e.g., policies)\n/// to explicitly define the types of values that they should (and will) be using in a future release.\ncontract ValueInterpreter is IValueInterpreter {\n    using SafeMath for uint256;\n\n    address private immutable AGGREGATED_DERIVATIVE_PRICE_FEED;\n    address private immutable PRIMITIVE_PRICE_FEED;\n\n    constructor(address _primitivePriceFeed, address _aggregatedDerivativePriceFeed) public {\n        AGGREGATED_DERIVATIVE_PRICE_FEED = _aggregatedDerivativePriceFeed;\n        PRIMITIVE_PRICE_FEED = _primitivePriceFeed;\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice An alias of calcCanonicalAssetsTotalValue\n    function calcLiveAssetsTotalValue(\n        address[] calldata _baseAssets,\n        uint256[] calldata _amounts,\n        address _quoteAsset\n    ) external override returns (uint256 value_, bool isValid_) {\n        return calcCanonicalAssetsTotalValue(_baseAssets, _amounts, _quoteAsset);\n    }\n\n    /// @notice An alias of calcCanonicalAssetValue\n    function calcLiveAssetValue(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset\n    ) external override returns (uint256 value_, bool isValid_) {\n        return calcCanonicalAssetValue(_baseAsset, _amount, _quoteAsset);\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Calculates the total value of given amounts of assets in a single quote asset\n    /// @param _baseAssets The assets to convert\n    /// @param _amounts The amounts of the _baseAssets to convert\n    /// @param _quoteAsset The asset to which to convert\n    /// @return value_ The sum value of _baseAssets, denominated in the _quoteAsset\n    /// @return isValid_ True if the price feed rates used to derive value are all valid\n    /// @dev Does not alter protocol state,\n    /// but not a view because calls to price feeds can potentially update third party state\n    function calcCanonicalAssetsTotalValue(\n        address[] memory _baseAssets,\n        uint256[] memory _amounts,\n        address _quoteAsset\n    ) public override returns (uint256 value_, bool isValid_) {\n        require(\n            _baseAssets.length == _amounts.length,\n            \"calcCanonicalAssetsTotalValue: Arrays unequal lengths\"\n        );\n        require(\n            IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_quoteAsset),\n            \"calcCanonicalAssetsTotalValue: Unsupported _quoteAsset\"\n        );\n\n        isValid_ = true;\n        for (uint256 i; i < _baseAssets.length; i++) {\n            (uint256 assetValue, bool assetValueIsValid) = __calcAssetValue(\n                _baseAssets[i],\n                _amounts[i],\n                _quoteAsset\n            );\n            value_ = value_.add(assetValue);\n            if (!assetValueIsValid) {\n                isValid_ = false;\n            }\n        }\n\n        return (value_, isValid_);\n    }\n\n    /// @notice Calculates the value of a given amount of one asset in terms of another asset\n    /// @param _baseAsset The asset from which to convert\n    /// @param _amount The amount of the _baseAsset to convert\n    /// @param _quoteAsset The asset to which to convert\n    /// @return value_ The equivalent quantity in the _quoteAsset\n    /// @return isValid_ True if the price feed rates used to derive value are all valid\n    /// @dev Does not alter protocol state,\n    /// but not a view because calls to price feeds can potentially update third party state\n    function calcCanonicalAssetValue(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset\n    ) public override returns (uint256 value_, bool isValid_) {\n        if (_baseAsset == _quoteAsset || _amount == 0) {\n            return (_amount, true);\n        }\n\n        require(\n            IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_quoteAsset),\n            \"calcCanonicalAssetValue: Unsupported _quoteAsset\"\n        );\n\n        return __calcAssetValue(_baseAsset, _amount, _quoteAsset);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to differentially calculate an asset value\n    /// based on if it is a primitive or derivative asset.\n    function __calcAssetValue(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset\n    ) private returns (uint256 value_, bool isValid_) {\n        if (_baseAsset == _quoteAsset || _amount == 0) {\n            return (_amount, true);\n        }\n\n        // Handle case that asset is a primitive\n        if (IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_baseAsset)) {\n            return\n                IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).calcCanonicalValue(\n                    _baseAsset,\n                    _amount,\n                    _quoteAsset\n                );\n        }\n\n        // Handle case that asset is a derivative\n        address derivativePriceFeed = IAggregatedDerivativePriceFeed(\n            AGGREGATED_DERIVATIVE_PRICE_FEED\n        )\n            .getPriceFeedForDerivative(_baseAsset);\n        if (derivativePriceFeed != address(0)) {\n            return __calcDerivativeValue(derivativePriceFeed, _baseAsset, _amount, _quoteAsset);\n        }\n\n        revert(\"__calcAssetValue: Unsupported _baseAsset\");\n    }\n\n    /// @dev Helper to calculate the value of a derivative in an arbitrary asset.\n    /// Handles multiple underlying assets (e.g., Uniswap and Balancer pool tokens).\n    /// Handles underlying assets that are also derivatives (e.g., a cDAI-ETH LP)\n    function __calcDerivativeValue(\n        address _derivativePriceFeed,\n        address _derivative,\n        uint256 _amount,\n        address _quoteAsset\n    ) private returns (uint256 value_, bool isValid_) {\n        (address[] memory underlyings, uint256[] memory underlyingAmounts) = IDerivativePriceFeed(\n            _derivativePriceFeed\n        )\n            .calcUnderlyingValues(_derivative, _amount);\n\n        require(underlyings.length > 0, \"__calcDerivativeValue: No underlyings\");\n        require(\n            underlyings.length == underlyingAmounts.length,\n            \"__calcDerivativeValue: Arrays unequal lengths\"\n        );\n\n        // Let validity be negated if any of the underlying value calculations are invalid\n        isValid_ = true;\n        for (uint256 i = 0; i < underlyings.length; i++) {\n            (uint256 underlyingValue, bool underlyingValueIsValid) = __calcAssetValue(\n                underlyings[i],\n                underlyingAmounts[i],\n                _quoteAsset\n            );\n\n            if (!underlyingValueIsValid) {\n                isValid_ = false;\n            }\n            value_ = value_.add(underlyingValue);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `AGGREGATED_DERIVATIVE_PRICE_FEED` variable\n    /// @return aggregatedDerivativePriceFeed_ The `AGGREGATED_DERIVATIVE_PRICE_FEED` variable value\n    function getAggregatedDerivativePriceFeed()\n        external\n        view\n        returns (address aggregatedDerivativePriceFeed_)\n    {\n        return AGGREGATED_DERIVATIVE_PRICE_FEED;\n    }\n\n    /// @notice Gets the `PRIMITIVE_PRICE_FEED` variable\n    /// @return primitivePriceFeed_ The `PRIMITIVE_PRICE_FEED` variable value\n    function getPrimitivePriceFeed() external view returns (address primitivePriceFeed_) {\n        return PRIMITIVE_PRICE_FEED;\n    }\n}\n"
      },
      "contracts/persistent/dispatcher/IDispatcher.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IDispatcher Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IDispatcher {\n    function cancelMigration(address _vaultProxy, bool _bypassFailure) external;\n\n    function claimOwnership() external;\n\n    function deployVaultProxy(\n        address _vaultLib,\n        address _owner,\n        address _vaultAccessor,\n        string calldata _fundName\n    ) external returns (address vaultProxy_);\n\n    function executeMigration(address _vaultProxy, bool _bypassFailure) external;\n\n    function getCurrentFundDeployer() external view returns (address currentFundDeployer_);\n\n    function getFundDeployerForVaultProxy(address _vaultProxy)\n        external\n        view\n        returns (address fundDeployer_);\n\n    function getMigrationRequestDetailsForVaultProxy(address _vaultProxy)\n        external\n        view\n        returns (\n            address nextFundDeployer_,\n            address nextVaultAccessor_,\n            address nextVaultLib_,\n            uint256 executableTimestamp_\n        );\n\n    function getMigrationTimelock() external view returns (uint256 migrationTimelock_);\n\n    function getNominatedOwner() external view returns (address nominatedOwner_);\n\n    function getOwner() external view returns (address owner_);\n\n    function getSharesTokenSymbol() external view returns (string memory sharesTokenSymbol_);\n\n    function getTimelockRemainingForMigrationRequest(address _vaultProxy)\n        external\n        view\n        returns (uint256 secondsRemaining_);\n\n    function hasExecutableMigrationRequest(address _vaultProxy)\n        external\n        view\n        returns (bool hasExecutableRequest_);\n\n    function hasMigrationRequest(address _vaultProxy)\n        external\n        view\n        returns (bool hasMigrationRequest_);\n\n    function removeNominatedOwner() external;\n\n    function setCurrentFundDeployer(address _nextFundDeployer) external;\n\n    function setMigrationTimelock(uint256 _nextTimelock) external;\n\n    function setNominatedOwner(address _nextNominatedOwner) external;\n\n    function setSharesTokenSymbol(string calldata _nextSymbol) external;\n\n    function signalMigration(\n        address _vaultProxy,\n        address _nextVaultAccessor,\n        address _nextVaultLib,\n        bool _bypassFailure\n    ) external;\n}\n"
      },
      "contracts/release/extensions/fee-manager/IFeeManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n/// @title FeeManager Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for the FeeManager\ninterface IFeeManager {\n    // No fees for the current release are implemented post-redeemShares\n    enum FeeHook {\n        Continuous,\n        BuySharesSetup,\n        PreBuyShares,\n        PostBuyShares,\n        BuySharesCompleted,\n        PreRedeemShares\n    }\n    enum SettlementType {None, Direct, Mint, Burn, MintSharesOutstanding, BurnSharesOutstanding}\n\n    function invokeHook(\n        FeeHook,\n        bytes calldata,\n        uint256\n    ) external;\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/primitives/IPrimitivePriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IPrimitivePriceFeed Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for primitive price feeds\ninterface IPrimitivePriceFeed {\n    function calcCanonicalValue(\n        address,\n        uint256,\n        address\n    ) external view returns (uint256, bool);\n\n    function calcLiveValue(\n        address,\n        uint256,\n        address\n    ) external view returns (uint256, bool);\n\n    function isSupportedAsset(address) external view returns (bool);\n}\n"
      },
      "contracts/release/infrastructure/value-interpreter/IValueInterpreter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IValueInterpreter interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for ValueInterpreter\ninterface IValueInterpreter {\n    function calcCanonicalAssetValue(\n        address,\n        uint256,\n        address\n    ) external returns (uint256, bool);\n\n    function calcCanonicalAssetsTotalValue(\n        address[] calldata,\n        uint256[] calldata,\n        address\n    ) external returns (uint256, bool);\n\n    function calcLiveAssetValue(\n        address,\n        uint256,\n        address\n    ) external returns (uint256, bool);\n\n    function calcLiveAssetsTotalValue(\n        address[] calldata,\n        uint256[] calldata,\n        address\n    ) external returns (uint256, bool);\n}\n"
      },
      "contracts/release/utils/AssetFinalityResolver.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../infrastructure/price-feeds/derivatives/feeds/SynthetixPriceFeed.sol\";\nimport \"../interfaces/ISynthetixAddressResolver.sol\";\nimport \"../interfaces/ISynthetixExchanger.sol\";\n\n/// @title AssetFinalityResolver Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A contract that helps achieve asset finality\nabstract contract AssetFinalityResolver {\n    address internal immutable SYNTHETIX_ADDRESS_RESOLVER;\n    address internal immutable SYNTHETIX_PRICE_FEED;\n\n    constructor(address _synthetixPriceFeed, address _synthetixAddressResolver) public {\n        SYNTHETIX_ADDRESS_RESOLVER = _synthetixAddressResolver;\n        SYNTHETIX_PRICE_FEED = _synthetixPriceFeed;\n    }\n\n    /// @dev Helper to finalize a Synth balance at a given target address and return its balance\n    function __finalizeIfSynthAndGetAssetBalance(\n        address _target,\n        address _asset,\n        bool _requireFinality\n    ) internal returns (uint256 assetBalance_) {\n        bytes32 currencyKey = SynthetixPriceFeed(SYNTHETIX_PRICE_FEED).getCurrencyKeyForSynth(\n            _asset\n        );\n        if (currencyKey != 0) {\n            address synthetixExchanger = ISynthetixAddressResolver(SYNTHETIX_ADDRESS_RESOLVER)\n                .requireAndGetAddress(\n                \"Exchanger\",\n                \"finalizeAndGetAssetBalance: Missing Exchanger\"\n            );\n            try ISynthetixExchanger(synthetixExchanger).settle(_target, currencyKey)  {} catch {\n                require(!_requireFinality, \"finalizeAndGetAssetBalance: Cannot settle Synth\");\n            }\n        }\n\n        return ERC20(_asset).balanceOf(_target);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `SYNTHETIX_ADDRESS_RESOLVER` variable\n    /// @return synthetixAddressResolver_ The `SYNTHETIX_ADDRESS_RESOLVER` variable value\n    function getSynthetixAddressResolver()\n        external\n        view\n        returns (address synthetixAddressResolver_)\n    {\n        return SYNTHETIX_ADDRESS_RESOLVER;\n    }\n\n    /// @notice Gets the `SYNTHETIX_PRICE_FEED` variable\n    /// @return synthetixPriceFeed_ The `SYNTHETIX_PRICE_FEED` variable value\n    function getSynthetixPriceFeed() external view returns (address synthetixPriceFeed_) {\n        return SYNTHETIX_PRICE_FEED;\n    }\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/feeds/SynthetixPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/ISynthetix.sol\";\nimport \"../../../../interfaces/ISynthetixAddressResolver.sol\";\nimport \"../../../../interfaces/ISynthetixExchangeRates.sol\";\nimport \"../../../../interfaces/ISynthetixProxyERC20.sol\";\nimport \"../../../../interfaces/ISynthetixSynth.sol\";\nimport \"../../../utils/DispatcherOwnerMixin.sol\";\nimport \"../IDerivativePriceFeed.sol\";\n\n/// @title SynthetixPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A price feed that uses Synthetix oracles as price sources\ncontract SynthetixPriceFeed is IDerivativePriceFeed, DispatcherOwnerMixin {\n    using SafeMath for uint256;\n\n    event SynthAdded(address indexed synth, bytes32 currencyKey);\n\n    event SynthCurrencyKeyUpdated(\n        address indexed synth,\n        bytes32 prevCurrencyKey,\n        bytes32 nextCurrencyKey\n    );\n\n    uint256 private constant SYNTH_UNIT = 10**18;\n    address private immutable ADDRESS_RESOLVER;\n    address private immutable SUSD;\n\n    mapping(address => bytes32) private synthToCurrencyKey;\n\n    constructor(\n        address _dispatcher,\n        address _addressResolver,\n        address _sUSD,\n        address[] memory _synths\n    ) public DispatcherOwnerMixin(_dispatcher) {\n        ADDRESS_RESOLVER = _addressResolver;\n        SUSD = _sUSD;\n\n        address[] memory sUSDSynths = new address[](1);\n        sUSDSynths[0] = _sUSD;\n\n        __addSynths(sUSDSynths);\n        __addSynths(_synths);\n    }\n\n    /// @notice Converts a given amount of a derivative to its underlying asset values\n    /// @param _derivative The derivative to convert\n    /// @param _derivativeAmount The amount of the derivative to convert\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The amount of each underlying asset for the equivalent derivative amount\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        underlyings_ = new address[](1);\n        underlyings_[0] = SUSD;\n        underlyingAmounts_ = new uint256[](1);\n\n        bytes32 currencyKey = getCurrencyKeyForSynth(_derivative);\n        require(currencyKey != 0, \"calcUnderlyingValues: _derivative is not supported\");\n\n        address exchangeRates = ISynthetixAddressResolver(ADDRESS_RESOLVER).requireAndGetAddress(\n            \"ExchangeRates\",\n            \"calcUnderlyingValues: Missing ExchangeRates\"\n        );\n\n        (uint256 rate, bool isInvalid) = ISynthetixExchangeRates(exchangeRates).rateAndInvalid(\n            currencyKey\n        );\n        require(!isInvalid, \"calcUnderlyingValues: _derivative rate is not valid\");\n\n        underlyingAmounts_[0] = _derivativeAmount.mul(rate).div(SYNTH_UNIT);\n\n        return (underlyings_, underlyingAmounts_);\n    }\n\n    /// @notice Checks whether an asset is a supported primitive of the price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is a supported primitive\n    function isSupportedAsset(address _asset) public view override returns (bool isSupported_) {\n        return getCurrencyKeyForSynth(_asset) != 0;\n    }\n\n    /////////////////////\n    // SYNTHS REGISTRY //\n    /////////////////////\n\n    /// @notice Adds Synths to the price feed\n    /// @param _synths Synths to add\n    function addSynths(address[] calldata _synths) external onlyDispatcherOwner {\n        require(_synths.length > 0, \"addSynths: Empty _synths\");\n\n        __addSynths(_synths);\n    }\n\n    /// @notice Updates the cached currencyKey value for specified Synths\n    /// @param _synths Synths to update\n    /// @dev Anybody can call this function\n    function updateSynthCurrencyKeys(address[] calldata _synths) external {\n        require(_synths.length > 0, \"updateSynthCurrencyKeys: Empty _synths\");\n\n        for (uint256 i; i < _synths.length; i++) {\n            bytes32 prevCurrencyKey = synthToCurrencyKey[_synths[i]];\n            require(prevCurrencyKey != 0, \"updateSynthCurrencyKeys: Synth not set\");\n\n            bytes32 nextCurrencyKey = __getCurrencyKey(_synths[i]);\n            require(\n                nextCurrencyKey != prevCurrencyKey,\n                \"updateSynthCurrencyKeys: Synth has correct currencyKey\"\n            );\n\n            synthToCurrencyKey[_synths[i]] = nextCurrencyKey;\n\n            emit SynthCurrencyKeyUpdated(_synths[i], prevCurrencyKey, nextCurrencyKey);\n        }\n    }\n\n    /// @dev Helper to add Synths\n    function __addSynths(address[] memory _synths) private {\n        for (uint256 i; i < _synths.length; i++) {\n            require(synthToCurrencyKey[_synths[i]] == 0, \"__addSynths: Value already set\");\n\n            bytes32 currencyKey = __getCurrencyKey(_synths[i]);\n            require(currencyKey != 0, \"__addSynths: No currencyKey\");\n\n            synthToCurrencyKey[_synths[i]] = currencyKey;\n\n            emit SynthAdded(_synths[i], currencyKey);\n        }\n    }\n\n    /// @dev Helper to query a currencyKey from Synthetix\n    function __getCurrencyKey(address _synthProxy) private view returns (bytes32 currencyKey_) {\n        return ISynthetixSynth(ISynthetixProxyERC20(_synthProxy).target()).currencyKey();\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `ADDRESS_RESOLVER` variable\n    /// @return addressResolver_ The `ADDRESS_RESOLVER` variable value\n    function getAddressResolver() external view returns (address) {\n        return ADDRESS_RESOLVER;\n    }\n\n    /// @notice Gets the currencyKey for multiple given Synths\n    /// @return currencyKeys_ The currencyKey values\n    function getCurrencyKeysForSynths(address[] calldata _synths)\n        external\n        view\n        returns (bytes32[] memory currencyKeys_)\n    {\n        currencyKeys_ = new bytes32[](_synths.length);\n        for (uint256 i; i < _synths.length; i++) {\n            currencyKeys_[i] = synthToCurrencyKey[_synths[i]];\n        }\n\n        return currencyKeys_;\n    }\n\n    /// @notice Gets the `SUSD` variable\n    /// @return susd_ The `SUSD` variable value\n    function getSUSD() external view returns (address susd_) {\n        return SUSD;\n    }\n\n    /// @notice Gets the currencyKey for a given Synth\n    /// @return currencyKey_ The currencyKey value\n    function getCurrencyKeyForSynth(address _synth) public view returns (bytes32 currencyKey_) {\n        return synthToCurrencyKey[_synth];\n    }\n}\n"
      },
      "contracts/release/interfaces/ISynthetixAddressResolver.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetixAddressResolver Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetixAddressResolver {\n    function requireAndGetAddress(bytes32, string calldata) external view returns (address);\n}\n"
      },
      "contracts/release/interfaces/ISynthetixExchanger.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetixExchanger Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetixExchanger {\n    function getAmountsForExchange(\n        uint256,\n        bytes32,\n        bytes32\n    )\n        external\n        view\n        returns (\n            uint256,\n            uint256,\n            uint256\n        );\n\n    function settle(address, bytes32)\n        external\n        returns (\n            uint256,\n            uint256,\n            uint256\n        );\n}\n"
      },
      "contracts/release/interfaces/ISynthetix.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetix Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetix {\n    function exchangeOnBehalfWithTracking(\n        address,\n        bytes32,\n        uint256,\n        bytes32,\n        address,\n        bytes32\n    ) external returns (uint256);\n}\n"
      },
      "contracts/release/interfaces/ISynthetixExchangeRates.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetixExchangeRates Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetixExchangeRates {\n    function rateAndInvalid(bytes32) external view returns (uint256, bool);\n}\n"
      },
      "contracts/release/interfaces/ISynthetixProxyERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetixProxyERC20 Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetixProxyERC20 {\n    function target() external view returns (address);\n}\n"
      },
      "contracts/release/interfaces/ISynthetixSynth.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ISynthetixSynth Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface ISynthetixSynth {\n    function currencyKey() external view returns (bytes32);\n}\n"
      },
      "contracts/release/infrastructure/utils/DispatcherOwnerMixin.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../persistent/dispatcher/IDispatcher.sol\";\n\n/// @title DispatcherOwnerMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract that defers ownership to the owner of Dispatcher\nabstract contract DispatcherOwnerMixin {\n    address internal immutable DISPATCHER;\n\n    modifier onlyDispatcherOwner() {\n        require(\n            msg.sender == getOwner(),\n            \"onlyDispatcherOwner: Only the Dispatcher owner can call this function\"\n        );\n        _;\n    }\n\n    constructor(address _dispatcher) public {\n        DISPATCHER = _dispatcher;\n    }\n\n    /// @notice Gets the owner of this contract\n    /// @return owner_ The owner\n    /// @dev Ownership is deferred to the owner of the Dispatcher contract\n    function getOwner() public view returns (address owner_) {\n        return IDispatcher(DISPATCHER).getOwner();\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `DISPATCHER` variable\n    /// @return dispatcher_ The `DISPATCHER` variable value\n    function getDispatcher() external view returns (address dispatcher_) {\n        return DISPATCHER;\n    }\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/IDerivativePriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IDerivativePriceFeed Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Simple interface for derivative price source oracle implementations\ninterface IDerivativePriceFeed {\n    function calcUnderlyingValues(address, uint256)\n        external\n        returns (address[] memory, uint256[] memory);\n\n    function isSupportedAsset(address) external view returns (bool);\n}\n"
      },
      "contracts/persistent/vault/VaultLibBase1.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./VaultLibBaseCore.sol\";\n\n/// @title VaultLibBase1 Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice The first implementation of VaultLibBaseCore, with additional events and storage\n/// @dev All subsequent implementations should inherit the previous implementation,\n/// e.g., `VaultLibBase2 is VaultLibBase1`\n/// DO NOT EDIT CONTRACT.\nabstract contract VaultLibBase1 is VaultLibBaseCore {\n    event AssetWithdrawn(address indexed asset, address indexed target, uint256 amount);\n\n    event TrackedAssetAdded(address asset);\n\n    event TrackedAssetRemoved(address asset);\n\n    address[] internal trackedAssets;\n    mapping(address => bool) internal assetToIsTracked;\n}\n"
      },
      "contracts/persistent/vault/VaultLibBaseCore.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/IMigratableVault.sol\";\nimport \"./utils/ProxiableVaultLib.sol\";\nimport \"./utils/SharesTokenBase.sol\";\n\n/// @title VaultLibBaseCore Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A persistent contract containing all required storage variables and\n/// required functions for a VaultLib implementation\n/// @dev DO NOT EDIT CONTRACT. If new events or storage are necessary, they should be added to\n/// a numbered VaultLibBaseXXX that inherits the previous base. See VaultLibBase1.\nabstract contract VaultLibBaseCore is IMigratableVault, ProxiableVaultLib, SharesTokenBase {\n    event AccessorSet(address prevAccessor, address nextAccessor);\n\n    event MigratorSet(address prevMigrator, address nextMigrator);\n\n    event OwnerSet(address prevOwner, address nextOwner);\n\n    event VaultLibSet(address prevVaultLib, address nextVaultLib);\n\n    address internal accessor;\n    address internal creator;\n    address internal migrator;\n    address internal owner;\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Initializes the VaultProxy with core configuration\n    /// @param _owner The address to set as the fund owner\n    /// @param _accessor The address to set as the permissioned accessor of the VaultLib\n    /// @param _fundName The name of the fund\n    /// @dev Serves as a per-proxy pseudo-constructor\n    function init(\n        address _owner,\n        address _accessor,\n        string calldata _fundName\n    ) external override {\n        require(creator == address(0), \"init: Proxy already initialized\");\n        creator = msg.sender;\n        sharesName = _fundName;\n\n        __setAccessor(_accessor);\n        __setOwner(_owner);\n\n        emit VaultLibSet(address(0), getVaultLib());\n    }\n\n    /// @notice Sets the permissioned accessor of the VaultLib\n    /// @param _nextAccessor The address to set as the permissioned accessor of the VaultLib\n    function setAccessor(address _nextAccessor) external override {\n        require(msg.sender == creator, \"setAccessor: Only callable by the contract creator\");\n\n        __setAccessor(_nextAccessor);\n    }\n\n    /// @notice Sets the VaultLib target for the VaultProxy\n    /// @param _nextVaultLib The address to set as the VaultLib\n    /// @dev This function is absolutely critical. __updateCodeAddress() validates that the\n    /// target is a valid Proxiable contract instance.\n    /// Does not block _nextVaultLib from being the same as the current VaultLib\n    function setVaultLib(address _nextVaultLib) external override {\n        require(msg.sender == creator, \"setVaultLib: Only callable by the contract creator\");\n\n        address prevVaultLib = getVaultLib();\n\n        __updateCodeAddress(_nextVaultLib);\n\n        emit VaultLibSet(prevVaultLib, _nextVaultLib);\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Checks whether an account is allowed to migrate the VaultProxy\n    /// @param _who The account to check\n    /// @return canMigrate_ True if the account is allowed to migrate the VaultProxy\n    function canMigrate(address _who) public view virtual override returns (bool canMigrate_) {\n        return _who == owner || _who == migrator;\n    }\n\n    /// @notice Gets the VaultLib target for the VaultProxy\n    /// @return vaultLib_ The address of the VaultLib target\n    function getVaultLib() public view returns (address vaultLib_) {\n        assembly {\n            // solium-disable-line\n            vaultLib_ := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)\n        }\n        return vaultLib_;\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Helper to set the permissioned accessor of the VaultProxy.\n    /// Does not prevent the prevAccessor from being the _nextAccessor.\n    function __setAccessor(address _nextAccessor) internal {\n        require(_nextAccessor != address(0), \"__setAccessor: _nextAccessor cannot be empty\");\n        address prevAccessor = accessor;\n\n        accessor = _nextAccessor;\n\n        emit AccessorSet(prevAccessor, _nextAccessor);\n    }\n\n    /// @dev Helper to set the owner of the VaultProxy\n    function __setOwner(address _nextOwner) internal {\n        require(_nextOwner != address(0), \"__setOwner: _nextOwner cannot be empty\");\n        address prevOwner = owner;\n        require(_nextOwner != prevOwner, \"__setOwner: _nextOwner is the current owner\");\n\n        owner = _nextOwner;\n\n        emit OwnerSet(prevOwner, _nextOwner);\n    }\n}\n"
      },
      "contracts/persistent/vault/utils/ProxiableVaultLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title ProxiableVaultLib Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A contract that defines the upgrade behavior for VaultLib instances\n/// @dev The recommended implementation of the target of a proxy according to EIP-1822 and EIP-1967\n/// Code position in storage is `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`,\n/// which is \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\".\nabstract contract ProxiableVaultLib {\n    /// @dev Updates the target of the proxy to be the contract at _nextVaultLib\n    function __updateCodeAddress(address _nextVaultLib) internal {\n        require(\n            bytes32(0x027b9570e9fedc1a80b937ae9a06861e5faef3992491af30b684a64b3fbec7a5) ==\n                ProxiableVaultLib(_nextVaultLib).proxiableUUID(),\n            \"__updateCodeAddress: _nextVaultLib not compatible\"\n        );\n        assembly {\n            // solium-disable-line\n            sstore(\n                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,\n                _nextVaultLib\n            )\n        }\n    }\n\n    /// @notice Returns a unique bytes32 hash for VaultLib instances\n    /// @return uuid_ The bytes32 hash representing the UUID\n    /// @dev The UUID is `bytes32(keccak256('mln.proxiable.vaultlib'))`\n    function proxiableUUID() public pure returns (bytes32 uuid_) {\n        return 0x027b9570e9fedc1a80b937ae9a06861e5faef3992491af30b684a64b3fbec7a5;\n    }\n}\n"
      },
      "contracts/persistent/vault/utils/SharesTokenBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./VaultLibSafeMath.sol\";\n\n/// @title StandardERC20 Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Contains the storage, events, and default logic of an ERC20-compliant contract.\n/// @dev The logic can be overridden by VaultLib implementations.\n/// Adapted from OpenZeppelin 3.2.0.\n/// DO NOT EDIT THIS CONTRACT.\nabstract contract SharesTokenBase {\n    using VaultLibSafeMath for uint256;\n\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    string internal sharesName;\n    string internal sharesSymbol;\n    uint256 internal sharesTotalSupply;\n    mapping(address => uint256) internal sharesBalances;\n    mapping(address => mapping(address => uint256)) internal sharesAllowances;\n\n    // EXTERNAL FUNCTIONS\n\n    /// @dev Standard implementation of ERC20's approve(). Can be overridden.\n    function approve(address _spender, uint256 _amount) public virtual returns (bool) {\n        __approve(msg.sender, _spender, _amount);\n        return true;\n    }\n\n    /// @dev Standard implementation of ERC20's transfer(). Can be overridden.\n    function transfer(address _recipient, uint256 _amount) public virtual returns (bool) {\n        __transfer(msg.sender, _recipient, _amount);\n        return true;\n    }\n\n    /// @dev Standard implementation of ERC20's transferFrom(). Can be overridden.\n    function transferFrom(\n        address _sender,\n        address _recipient,\n        uint256 _amount\n    ) public virtual returns (bool) {\n        __transfer(_sender, _recipient, _amount);\n        __approve(\n            _sender,\n            msg.sender,\n            sharesAllowances[_sender][msg.sender].sub(\n                _amount,\n                \"ERC20: transfer amount exceeds allowance\"\n            )\n        );\n        return true;\n    }\n\n    // EXTERNAL FUNCTIONS - VIEW\n\n    /// @dev Standard implementation of ERC20's allowance(). Can be overridden.\n    function allowance(address _owner, address _spender) public view virtual returns (uint256) {\n        return sharesAllowances[_owner][_spender];\n    }\n\n    /// @dev Standard implementation of ERC20's balanceOf(). Can be overridden.\n    function balanceOf(address _account) public view virtual returns (uint256) {\n        return sharesBalances[_account];\n    }\n\n    /// @dev Standard implementation of ERC20's decimals(). Can not be overridden.\n    function decimals() public pure returns (uint8) {\n        return 18;\n    }\n\n    /// @dev Standard implementation of ERC20's name(). Can be overridden.\n    function name() public view virtual returns (string memory) {\n        return sharesName;\n    }\n\n    /// @dev Standard implementation of ERC20's symbol(). Can be overridden.\n    function symbol() public view virtual returns (string memory) {\n        return sharesSymbol;\n    }\n\n    /// @dev Standard implementation of ERC20's totalSupply(). Can be overridden.\n    function totalSupply() public view virtual returns (uint256) {\n        return sharesTotalSupply;\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Helper for approve(). Can be overridden.\n    function __approve(\n        address _owner,\n        address _spender,\n        uint256 _amount\n    ) 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        sharesAllowances[_owner][_spender] = _amount;\n        emit Approval(_owner, _spender, _amount);\n    }\n\n    /// @dev Helper to burn tokens from an account. Can be overridden.\n    function __burn(address _account, uint256 _amount) internal virtual {\n        require(_account != address(0), \"ERC20: burn from the zero address\");\n\n        sharesBalances[_account] = sharesBalances[_account].sub(\n            _amount,\n            \"ERC20: burn amount exceeds balance\"\n        );\n        sharesTotalSupply = sharesTotalSupply.sub(_amount);\n        emit Transfer(_account, address(0), _amount);\n    }\n\n    /// @dev Helper to mint tokens to an account. Can be overridden.\n    function __mint(address _account, uint256 _amount) internal virtual {\n        require(_account != address(0), \"ERC20: mint to the zero address\");\n\n        sharesTotalSupply = sharesTotalSupply.add(_amount);\n        sharesBalances[_account] = sharesBalances[_account].add(_amount);\n        emit Transfer(address(0), _account, _amount);\n    }\n\n    /// @dev Helper to transfer tokens between accounts. Can be overridden.\n    function __transfer(\n        address _sender,\n        address _recipient,\n        uint256 _amount\n    ) 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        sharesBalances[_sender] = sharesBalances[_sender].sub(\n            _amount,\n            \"ERC20: transfer amount exceeds balance\"\n        );\n        sharesBalances[_recipient] = sharesBalances[_recipient].add(_amount);\n        emit Transfer(_sender, _recipient, _amount);\n    }\n}\n"
      },
      "contracts/persistent/vault/utils/VaultLibSafeMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title VaultLibSafeMath library\n/// @notice A narrowed, verbatim implementation of OpenZeppelin 3.2.0 SafeMath\n/// for use with VaultLib\n/// @dev Preferred to importing from npm to guarantee consistent logic and revert reasons\n/// between VaultLib implementations\n/// DO NOT EDIT THIS CONTRACT\nlibrary VaultLibSafeMath {\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c >= a, \"VaultLibSafeMath: addition overflow\");\n\n        return c;\n    }\n\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return sub(a, b, \"VaultLibSafeMath: subtraction overflow\");\n    }\n\n    function sub(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        require(b <= a, errorMessage);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b, \"VaultLibSafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return div(a, b, \"VaultLibSafeMath: division by zero\");\n    }\n\n    function div(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        uint256 c = a / b;\n\n        return c;\n    }\n\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return mod(a, b, \"VaultLibSafeMath: modulo by zero\");\n    }\n\n    function mod(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        require(b != 0, errorMessage);\n        return a % b;\n    }\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/IAggregatedDerivativePriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./IDerivativePriceFeed.sol\";\n\n/// @title IDerivativePriceFeed Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IAggregatedDerivativePriceFeed is IDerivativePriceFeed {\n    function getPriceFeedForDerivative(address) external view returns (address);\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/feeds/UniswapV2PoolPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../../../interfaces/IUniswapV2Pair.sol\";\nimport \"../../../../utils/MathHelpers.sol\";\nimport \"../../../utils/DispatcherOwnerMixin.sol\";\nimport \"../../../value-interpreter/ValueInterpreter.sol\";\nimport \"../../primitives/IPrimitivePriceFeed.sol\";\nimport \"../../utils/UniswapV2PoolTokenValueCalculator.sol\";\nimport \"../IDerivativePriceFeed.sol\";\n\n/// @title UniswapV2PoolPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Price feed for Uniswap lending pool tokens\ncontract UniswapV2PoolPriceFeed is\n    IDerivativePriceFeed,\n    DispatcherOwnerMixin,\n    MathHelpers,\n    UniswapV2PoolTokenValueCalculator\n{\n    event PoolTokenAdded(address indexed poolToken, address token0, address token1);\n\n    struct PoolTokenInfo {\n        address token0;\n        address token1;\n        uint8 token0Decimals;\n        uint8 token1Decimals;\n    }\n\n    uint256 private constant POOL_TOKEN_UNIT = 10**18;\n    address private immutable DERIVATIVE_PRICE_FEED;\n    address private immutable FACTORY;\n    address private immutable PRIMITIVE_PRICE_FEED;\n    address private immutable VALUE_INTERPRETER;\n\n    mapping(address => PoolTokenInfo) private poolTokenToInfo;\n\n    constructor(\n        address _dispatcher,\n        address _derivativePriceFeed,\n        address _primitivePriceFeed,\n        address _valueInterpreter,\n        address _factory,\n        address[] memory _poolTokens\n    ) public DispatcherOwnerMixin(_dispatcher) {\n        DERIVATIVE_PRICE_FEED = _derivativePriceFeed;\n        FACTORY = _factory;\n        PRIMITIVE_PRICE_FEED = _primitivePriceFeed;\n        VALUE_INTERPRETER = _valueInterpreter;\n\n        __addPoolTokens(_poolTokens, _derivativePriceFeed, _primitivePriceFeed);\n    }\n\n    /// @notice Converts a given amount of a derivative to its underlying asset values\n    /// @param _derivative The derivative to convert\n    /// @param _derivativeAmount The amount of the derivative to convert\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The amount of each underlying asset for the equivalent derivative amount\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        PoolTokenInfo memory poolTokenInfo = poolTokenToInfo[_derivative];\n\n        underlyings_ = new address[](2);\n        underlyings_[0] = poolTokenInfo.token0;\n        underlyings_[1] = poolTokenInfo.token1;\n\n        // Calculate the amounts underlying one unit of a pool token,\n        // taking into account the known, trusted rate between the two underlyings\n        (uint256 token0TrustedRateAmount, uint256 token1TrustedRateAmount) = __calcTrustedRate(\n            poolTokenInfo.token0,\n            poolTokenInfo.token1,\n            poolTokenInfo.token0Decimals,\n            poolTokenInfo.token1Decimals\n        );\n\n        (\n            uint256 token0DenormalizedRate,\n            uint256 token1DenormalizedRate\n        ) = __calcTrustedPoolTokenValue(\n            FACTORY,\n            _derivative,\n            token0TrustedRateAmount,\n            token1TrustedRateAmount\n        );\n\n        // Define normalized rates for each underlying\n        underlyingAmounts_ = new uint256[](2);\n        underlyingAmounts_[0] = _derivativeAmount.mul(token0DenormalizedRate).div(POOL_TOKEN_UNIT);\n        underlyingAmounts_[1] = _derivativeAmount.mul(token1DenormalizedRate).div(POOL_TOKEN_UNIT);\n\n        return (underlyings_, underlyingAmounts_);\n    }\n\n    /// @notice Checks if an asset is supported by the price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is supported\n    function isSupportedAsset(address _asset) public view override returns (bool isSupported_) {\n        return poolTokenToInfo[_asset].token0 != address(0);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Calculates the trusted rate of two assets based on our price feeds.\n    /// Uses the decimals-derived unit for whichever asset is used as the quote asset.\n    function __calcTrustedRate(\n        address _token0,\n        address _token1,\n        uint256 _token0Decimals,\n        uint256 _token1Decimals\n    ) private returns (uint256 token0RateAmount_, uint256 token1RateAmount_) {\n        bool rateIsValid;\n        // The quote asset of the value lookup must be a supported primitive asset,\n        // so we cycle through the tokens until reaching a primitive.\n        // If neither is a primitive, will revert at the ValueInterpreter\n        if (IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_token0)) {\n            token1RateAmount_ = 10**_token1Decimals;\n            (token0RateAmount_, rateIsValid) = ValueInterpreter(VALUE_INTERPRETER)\n                .calcCanonicalAssetValue(_token1, token1RateAmount_, _token0);\n        } else {\n            token0RateAmount_ = 10**_token0Decimals;\n            (token1RateAmount_, rateIsValid) = ValueInterpreter(VALUE_INTERPRETER)\n                .calcCanonicalAssetValue(_token0, token0RateAmount_, _token1);\n        }\n\n        require(rateIsValid, \"__calcTrustedRate: Invalid rate\");\n\n        return (token0RateAmount_, token1RateAmount_);\n    }\n\n    //////////////////////////\n    // POOL TOKENS REGISTRY //\n    //////////////////////////\n\n    /// @notice Adds Uniswap pool tokens to the price feed\n    /// @param _poolTokens Uniswap pool tokens to add\n    function addPoolTokens(address[] calldata _poolTokens) external onlyDispatcherOwner {\n        require(_poolTokens.length > 0, \"addPoolTokens: Empty _poolTokens\");\n\n        __addPoolTokens(_poolTokens, DERIVATIVE_PRICE_FEED, PRIMITIVE_PRICE_FEED);\n    }\n\n    /// @dev Helper to add Uniswap pool tokens\n    function __addPoolTokens(\n        address[] memory _poolTokens,\n        address _derivativePriceFeed,\n        address _primitivePriceFeed\n    ) private {\n        for (uint256 i; i < _poolTokens.length; i++) {\n            require(_poolTokens[i] != address(0), \"__addPoolTokens: Empty poolToken\");\n            require(\n                poolTokenToInfo[_poolTokens[i]].token0 == address(0),\n                \"__addPoolTokens: Value already set\"\n            );\n\n            IUniswapV2Pair uniswapV2Pair = IUniswapV2Pair(_poolTokens[i]);\n            address token0 = uniswapV2Pair.token0();\n            address token1 = uniswapV2Pair.token1();\n\n            require(\n                __poolTokenIsSupportable(\n                    _derivativePriceFeed,\n                    _primitivePriceFeed,\n                    token0,\n                    token1\n                ),\n                \"__addPoolTokens: Unsupported pool token\"\n            );\n\n            poolTokenToInfo[_poolTokens[i]] = PoolTokenInfo({\n                token0: token0,\n                token1: token1,\n                token0Decimals: ERC20(token0).decimals(),\n                token1Decimals: ERC20(token1).decimals()\n            });\n\n            emit PoolTokenAdded(_poolTokens[i], token0, token1);\n        }\n    }\n\n    /// @dev Helper to determine if a pool token is supportable, based on whether price feeds are\n    /// available for its underlying feeds. At least one of the underlying tokens must be\n    /// a supported primitive asset, and the other must be a primitive or derivative.\n    function __poolTokenIsSupportable(\n        address _derivativePriceFeed,\n        address _primitivePriceFeed,\n        address _token0,\n        address _token1\n    ) private view returns (bool isSupportable_) {\n        IDerivativePriceFeed derivativePriceFeedContract = IDerivativePriceFeed(\n            _derivativePriceFeed\n        );\n        IPrimitivePriceFeed primitivePriceFeedContract = IPrimitivePriceFeed(_primitivePriceFeed);\n\n        if (primitivePriceFeedContract.isSupportedAsset(_token0)) {\n            if (\n                primitivePriceFeedContract.isSupportedAsset(_token1) ||\n                derivativePriceFeedContract.isSupportedAsset(_token1)\n            ) {\n                return true;\n            }\n        } else if (\n            derivativePriceFeedContract.isSupportedAsset(_token0) &&\n            primitivePriceFeedContract.isSupportedAsset(_token1)\n        ) {\n            return true;\n        }\n\n        return false;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `DERIVATIVE_PRICE_FEED` variable value\n    /// @return derivativePriceFeed_ The `DERIVATIVE_PRICE_FEED` variable value\n    function getDerivativePriceFeed() external view returns (address derivativePriceFeed_) {\n        return DERIVATIVE_PRICE_FEED;\n    }\n\n    /// @notice Gets the `FACTORY` variable value\n    /// @return factory_ The `FACTORY` variable value\n    function getFactory() external view returns (address factory_) {\n        return FACTORY;\n    }\n\n    /// @notice Gets the `PoolTokenInfo` for a given pool token\n    /// @param _poolToken The pool token for which to get the `PoolTokenInfo`\n    /// @return poolTokenInfo_ The `PoolTokenInfo` value\n    function getPoolTokenInfo(address _poolToken)\n        external\n        view\n        returns (PoolTokenInfo memory poolTokenInfo_)\n    {\n        return poolTokenToInfo[_poolToken];\n    }\n\n    /// @notice Gets the underlyings for a given pool token\n    /// @param _poolToken The pool token for which to get its underlyings\n    /// @return token0_ The UniswapV2Pair.token0 value\n    /// @return token1_ The UniswapV2Pair.token1 value\n    function getPoolTokenUnderlyings(address _poolToken)\n        external\n        view\n        returns (address token0_, address token1_)\n    {\n        return (poolTokenToInfo[_poolToken].token0, poolTokenToInfo[_poolToken].token1);\n    }\n\n    /// @notice Gets the `PRIMITIVE_PRICE_FEED` variable value\n    /// @return primitivePriceFeed_ The `PRIMITIVE_PRICE_FEED` variable value\n    function getPrimitivePriceFeed() external view returns (address primitivePriceFeed_) {\n        return PRIMITIVE_PRICE_FEED;\n    }\n\n    /// @notice Gets the `VALUE_INTERPRETER` variable value\n    /// @return valueInterpreter_ The `VALUE_INTERPRETER` variable value\n    function getValueInterpreter() external view returns (address valueInterpreter_) {\n        return VALUE_INTERPRETER;\n    }\n}\n"
      },
      "contracts/release/interfaces/IUniswapV2Pair.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IUniswapV2Pair Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Minimal interface for our interactions with the Uniswap V2's Pair contract\ninterface IUniswapV2Pair {\n    function getReserves()\n        external\n        view\n        returns (\n            uint112,\n            uint112,\n            uint32\n        );\n\n    function kLast() external view returns (uint256);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function totalSupply() external view returns (uint256);\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/utils/UniswapV2PoolTokenValueCalculator.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../interfaces/IUniswapV2Factory.sol\";\nimport \"../../../interfaces/IUniswapV2Pair.sol\";\n\n/// @title UniswapV2PoolTokenValueCalculator Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Abstract contract for computing the value of Uniswap liquidity pool tokens\n/// @dev Unless otherwise noted, these functions are adapted to our needs and style guide from\n/// an un-merged Uniswap branch:\n/// https://github.com/Uniswap/uniswap-v2-periphery/blob/267ba44471f3357071a2fe2573fe4da42d5ad969/contracts/libraries/UniswapV2LiquidityMathLibrary.sol\nabstract contract UniswapV2PoolTokenValueCalculator {\n    using SafeMath for uint256;\n\n    uint256 private constant POOL_TOKEN_UNIT = 10**18;\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Given a Uniswap pool with token0 and token1 and their trusted rate,\n    /// returns the value of one pool token unit in terms of token0 and token1.\n    /// This is the only function used outside of this contract.\n    function __calcTrustedPoolTokenValue(\n        address _factory,\n        address _pair,\n        uint256 _token0TrustedRateAmount,\n        uint256 _token1TrustedRateAmount\n    ) internal view returns (uint256 token0Amount_, uint256 token1Amount_) {\n        (uint256 reserve0, uint256 reserve1) = __calcReservesAfterArbitrage(\n            _pair,\n            _token0TrustedRateAmount,\n            _token1TrustedRateAmount\n        );\n\n        return __calcPoolTokenValue(_factory, _pair, reserve0, reserve1);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Computes liquidity value given all the parameters of the pair\n    function __calcPoolTokenValue(\n        address _factory,\n        address _pair,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) private view returns (uint256 token0Amount_, uint256 token1Amount_) {\n        IUniswapV2Pair pairContract = IUniswapV2Pair(_pair);\n        uint256 totalSupply = pairContract.totalSupply();\n\n        if (IUniswapV2Factory(_factory).feeTo() != address(0)) {\n            uint256 kLast = pairContract.kLast();\n            if (kLast > 0) {\n                uint256 rootK = __uniswapSqrt(_reserve0.mul(_reserve1));\n                uint256 rootKLast = __uniswapSqrt(kLast);\n                if (rootK > rootKLast) {\n                    uint256 numerator = totalSupply.mul(rootK.sub(rootKLast));\n                    uint256 denominator = rootK.mul(5).add(rootKLast);\n                    uint256 feeLiquidity = numerator.div(denominator);\n                    totalSupply = totalSupply.add(feeLiquidity);\n                }\n            }\n        }\n        return (\n            _reserve0.mul(POOL_TOKEN_UNIT).div(totalSupply),\n            _reserve1.mul(POOL_TOKEN_UNIT).div(totalSupply)\n        );\n    }\n\n    /// @dev Calculates the direction and magnitude of the profit-maximizing trade\n    function __calcProfitMaximizingTrade(\n        uint256 _token0TrustedRateAmount,\n        uint256 _token1TrustedRateAmount,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) private pure returns (bool token0ToToken1_, uint256 amountIn_) {\n        token0ToToken1_ =\n            _reserve0.mul(_token1TrustedRateAmount).div(_reserve1) < _token0TrustedRateAmount;\n\n        uint256 leftSide;\n        uint256 rightSide;\n        if (token0ToToken1_) {\n            leftSide = __uniswapSqrt(\n                _reserve0.mul(_reserve1).mul(_token0TrustedRateAmount).mul(1000).div(\n                    _token1TrustedRateAmount.mul(997)\n                )\n            );\n            rightSide = _reserve0.mul(1000).div(997);\n        } else {\n            leftSide = __uniswapSqrt(\n                _reserve0.mul(_reserve1).mul(_token1TrustedRateAmount).mul(1000).div(\n                    _token0TrustedRateAmount.mul(997)\n                )\n            );\n            rightSide = _reserve1.mul(1000).div(997);\n        }\n\n        if (leftSide < rightSide) {\n            return (false, 0);\n        }\n\n        // Calculate the amount that must be sent to move the price to the profit-maximizing price\n        amountIn_ = leftSide.sub(rightSide);\n\n        return (token0ToToken1_, amountIn_);\n    }\n\n    /// @dev Calculates the pool reserves after an arbitrage moves the price to\n    /// the profit-maximizing rate, given an externally-observed trusted rate\n    /// between the two pooled assets\n    function __calcReservesAfterArbitrage(\n        address _pair,\n        uint256 _token0TrustedRateAmount,\n        uint256 _token1TrustedRateAmount\n    ) private view returns (uint256 reserve0_, uint256 reserve1_) {\n        (reserve0_, reserve1_, ) = IUniswapV2Pair(_pair).getReserves();\n\n        // Skip checking whether the reserve is 0, as this is extremely unlikely given how\n        // initial pool liquidity is locked, and since we maintain a list of registered pool tokens\n\n        // Calculate how much to swap to arb to the trusted price\n        (bool token0ToToken1, uint256 amountIn) = __calcProfitMaximizingTrade(\n            _token0TrustedRateAmount,\n            _token1TrustedRateAmount,\n            reserve0_,\n            reserve1_\n        );\n        if (amountIn == 0) {\n            return (reserve0_, reserve1_);\n        }\n\n        // Adjust the reserves to account for the arb trade to the trusted price\n        if (token0ToToken1) {\n            uint256 amountOut = __uniswapV2GetAmountOut(amountIn, reserve0_, reserve1_);\n            reserve0_ = reserve0_.add(amountIn);\n            reserve1_ = reserve1_.sub(amountOut);\n        } else {\n            uint256 amountOut = __uniswapV2GetAmountOut(amountIn, reserve1_, reserve0_);\n            reserve1_ = reserve1_.add(amountIn);\n            reserve0_ = reserve0_.sub(amountOut);\n        }\n\n        return (reserve0_, reserve1_);\n    }\n\n    /// @dev Uniswap square root function. See:\n    /// https://github.com/Uniswap/uniswap-lib/blob/6ddfedd5716ba85b905bf34d7f1f3c659101a1bc/contracts/libraries/Babylonian.sol\n    function __uniswapSqrt(uint256 _y) private pure returns (uint256 z_) {\n        if (_y > 3) {\n            z_ = _y;\n            uint256 x = _y / 2 + 1;\n            while (x < z_) {\n                z_ = x;\n                x = (_y / x + x) / 2;\n            }\n        } else if (_y != 0) {\n            z_ = 1;\n        }\n        // else z_ = 0\n\n        return z_;\n    }\n\n    /// @dev Simplified version of UniswapV2Library's getAmountOut() function. See:\n    /// https://github.com/Uniswap/uniswap-v2-periphery/blob/87edfdcaf49ccc52591502993db4c8c08ea9eec0/contracts/libraries/UniswapV2Library.sol#L42-L50\n    function __uniswapV2GetAmountOut(\n        uint256 _amountIn,\n        uint256 _reserveIn,\n        uint256 _reserveOut\n    ) private pure returns (uint256 amountOut_) {\n        uint256 amountInWithFee = _amountIn.mul(997);\n        uint256 numerator = amountInWithFee.mul(_reserveOut);\n        uint256 denominator = _reserveIn.mul(1000).add(amountInWithFee);\n\n        return numerator.div(denominator);\n    }\n}\n"
      },
      "contracts/release/interfaces/IUniswapV2Factory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IUniswapV2Factory Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Minimal interface for our interactions with the Uniswap V2's Factory contract\ninterface IUniswapV2Factory {\n    function feeTo() external view returns (address);\n\n    function getPair(address, address) external view returns (address);\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/feeds/WdgldPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/IChainlinkAggregator.sol\";\nimport \"../../../../utils/MakerDaoMath.sol\";\nimport \"../IDerivativePriceFeed.sol\";\n\n/// @title WdgldPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Price source oracle for WDGLD <https://dgld.ch/>\ncontract WdgldPriceFeed is IDerivativePriceFeed, MakerDaoMath {\n    using SafeMath for uint256;\n\n    address private immutable XAU_AGGREGATOR;\n    address private immutable ETH_AGGREGATOR;\n\n    address private immutable WDGLD;\n    address private immutable WETH;\n\n    // GTR_CONSTANT aggregates all the invariants in the GTR formula to save gas\n    uint256 private constant GTR_CONSTANT = 999990821653213975346065101;\n    uint256 private constant GTR_PRECISION = 10**27;\n    uint256 private constant WDGLD_GENESIS_TIMESTAMP = 1568700000;\n\n    constructor(\n        address _wdgld,\n        address _weth,\n        address _ethAggregator,\n        address _xauAggregator\n    ) public {\n        WDGLD = _wdgld;\n        WETH = _weth;\n        ETH_AGGREGATOR = _ethAggregator;\n        XAU_AGGREGATOR = _xauAggregator;\n    }\n\n    /// @notice Converts a given amount of a derivative to its underlying asset values\n    /// @param _derivative The derivative to convert\n    /// @param _derivativeAmount The amount of the derivative to convert\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The amount of each underlying asset for the equivalent derivative amount\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        require(isSupportedAsset(_derivative), \"calcUnderlyingValues: Only WDGLD is supported\");\n\n        underlyings_ = new address[](1);\n        underlyings_[0] = WETH;\n        underlyingAmounts_ = new uint256[](1);\n\n        // Get price rates from xau and eth aggregators\n        int256 xauToUsdRate = IChainlinkAggregator(XAU_AGGREGATOR).latestAnswer();\n        int256 ethToUsdRate = IChainlinkAggregator(ETH_AGGREGATOR).latestAnswer();\n        require(xauToUsdRate > 0 && ethToUsdRate > 0, \"calcUnderlyingValues: rate invalid\");\n\n        uint256 wdgldToXauRate = calcWdgldToXauRate();\n\n        // 10**17 is a combination of ETH_UNIT / WDGLD_UNIT * GTR_PRECISION\n        underlyingAmounts_[0] = _derivativeAmount\n            .mul(wdgldToXauRate)\n            .mul(uint256(xauToUsdRate))\n            .div(uint256(ethToUsdRate))\n            .div(10**17);\n\n        return (underlyings_, underlyingAmounts_);\n    }\n\n    /// @notice Calculates the rate of WDGLD to XAU.\n    /// @return wdgldToXauRate_ The current rate of WDGLD to XAU\n    /// @dev Full formula available <https://dgld.ch/assets/documents/dgld-whitepaper.pdf>\n    function calcWdgldToXauRate() public view returns (uint256 wdgldToXauRate_) {\n        return\n            __rpow(\n                GTR_CONSTANT,\n                ((block.timestamp).sub(WDGLD_GENESIS_TIMESTAMP)).div(28800), // 60 * 60 * 8 (8 hour periods)\n                GTR_PRECISION\n            )\n                .div(10);\n    }\n\n    /// @notice Checks if an asset is supported by this price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if supported\n    function isSupportedAsset(address _asset) public view override returns (bool isSupported_) {\n        return _asset == WDGLD;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `ETH_AGGREGATOR` address\n    /// @return ethAggregatorAddress_ The `ETH_AGGREGATOR` address\n    function getEthAggregator() external view returns (address ethAggregatorAddress_) {\n        return ETH_AGGREGATOR;\n    }\n\n    /// @notice Gets the `WDGLD` token address\n    /// @return wdgld_ The `WDGLD` token address\n    function getWdgld() external view returns (address wdgld_) {\n        return WDGLD;\n    }\n\n    /// @notice Gets the `WETH` token address\n    /// @return weth_ The `WETH` token address\n    function getWeth() external view returns (address weth_) {\n        return WETH;\n    }\n\n    /// @notice Gets the `XAU_AGGREGATOR` address\n    /// @return xauAggregatorAddress_ The `XAU_AGGREGATOR` address\n    function getXauAggregator() external view returns (address xauAggregatorAddress_) {\n        return XAU_AGGREGATOR;\n    }\n}\n"
      },
      "contracts/release/interfaces/IChainlinkAggregator.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IChainlinkAggregator Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IChainlinkAggregator {\n    function latestAnswer() external view returns (int256);\n\n    function latestTimestamp() external view returns (uint256);\n}\n"
      },
      "contracts/release/utils/MakerDaoMath.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n// Copyright (C) 2018 Rain <rainbreak@riseup.net>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\npragma solidity 0.6.12;\n\n/// @title MakerDaoMath Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Helper functions for math operations adapted from MakerDao contracts\nabstract contract MakerDaoMath {\n    /// @dev Performs scaled, fixed-point exponentiation.\n    /// Verbatim code, adapted to our style guide for variable naming only, see:\n    /// https://github.com/makerdao/dss/blob/master/src/pot.sol#L83-L105\n    // prettier-ignore\n    function __rpow(uint256 _x, uint256 _n, uint256 _base) internal pure returns (uint256 z_) {\n        assembly {\n            switch _x case 0 {switch _n case 0 {z_ := _base} default {z_ := 0}}\n            default {\n                switch mod(_n, 2) case 0 { z_ := _base } default { z_ := _x }\n                let half := div(_base, 2)\n                for { _n := div(_n, 2) } _n { _n := div(_n,2) } {\n                    let xx := mul(_x, _x)\n                    if iszero(eq(div(xx, _x), _x)) { revert(0,0) }\n                    let xxRound := add(xx, half)\n                    if lt(xxRound, xx) { revert(0,0) }\n                    _x := div(xxRound, _base)\n                    if mod(_n,2) {\n                        let zx := mul(z_, _x)\n                        if and(iszero(iszero(_x)), iszero(eq(div(zx, _x), z_))) { revert(0,0) }\n                        let zxRound := add(zx, half)\n                        if lt(zxRound, zx) { revert(0,0) }\n                        z_ := div(zxRound, _base)\n                    }\n                }\n            }\n        }\n\n        return z_;\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/ManagementFee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../core/fund/vault/VaultLib.sol\";\nimport \"../../../utils/MakerDaoMath.sol\";\nimport \"./utils/FeeBase.sol\";\n\n/// @title ManagementFee Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A management fee with a configurable annual rate\ncontract ManagementFee is FeeBase, MakerDaoMath {\n    using SafeMath for uint256;\n\n    event FundSettingsAdded(address indexed comptrollerProxy, uint256 scaledPerSecondRate);\n\n    event Settled(\n        address indexed comptrollerProxy,\n        uint256 sharesQuantity,\n        uint256 secondsSinceSettlement\n    );\n\n    struct FeeInfo {\n        uint256 scaledPerSecondRate;\n        uint256 lastSettled;\n    }\n\n    uint256 private constant RATE_SCALE_BASE = 10**27;\n\n    mapping(address => FeeInfo) private comptrollerProxyToFeeInfo;\n\n    constructor(address _feeManager) public FeeBase(_feeManager) {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Activates the fee for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _vaultProxy The VaultProxy of the fund\n    function activateForFund(address _comptrollerProxy, address _vaultProxy)\n        external\n        override\n        onlyFeeManager\n    {\n        // It is only necessary to set `lastSettled` for a migrated fund\n        if (VaultLib(_vaultProxy).totalSupply() > 0) {\n            comptrollerProxyToFeeInfo[_comptrollerProxy].lastSettled = block.timestamp;\n        }\n    }\n\n    /// @notice Add the initial fee settings for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _settingsData Encoded settings to apply to the fee for a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _settingsData)\n        external\n        override\n        onlyFeeManager\n    {\n        uint256 scaledPerSecondRate = abi.decode(_settingsData, (uint256));\n        require(\n            scaledPerSecondRate > 0,\n            \"addFundSettings: scaledPerSecondRate must be greater than 0\"\n        );\n\n        comptrollerProxyToFeeInfo[_comptrollerProxy] = FeeInfo({\n            scaledPerSecondRate: scaledPerSecondRate,\n            lastSettled: 0\n        });\n\n        emit FundSettingsAdded(_comptrollerProxy, scaledPerSecondRate);\n    }\n\n    /// @notice Provides a constant string identifier for a fee\n    /// @return identifier_ The identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"MANAGEMENT\";\n    }\n\n    /// @notice Gets the hooks that are implemented by the fee\n    /// @return implementedHooksForSettle_ The hooks during which settle() is implemented\n    /// @return implementedHooksForUpdate_ The hooks during which update() is implemented\n    /// @return usesGavOnSettle_ True if GAV is used during the settle() implementation\n    /// @return usesGavOnUpdate_ True if GAV is used during the update() implementation\n    /// @dev Used only during fee registration\n    function implementedHooks()\n        external\n        view\n        override\n        returns (\n            IFeeManager.FeeHook[] memory implementedHooksForSettle_,\n            IFeeManager.FeeHook[] memory implementedHooksForUpdate_,\n            bool usesGavOnSettle_,\n            bool usesGavOnUpdate_\n        )\n    {\n        implementedHooksForSettle_ = new IFeeManager.FeeHook[](3);\n        implementedHooksForSettle_[0] = IFeeManager.FeeHook.Continuous;\n        implementedHooksForSettle_[1] = IFeeManager.FeeHook.BuySharesSetup;\n        implementedHooksForSettle_[2] = IFeeManager.FeeHook.PreRedeemShares;\n\n        return (implementedHooksForSettle_, new IFeeManager.FeeHook[](0), false, false);\n    }\n\n    /// @notice Settle the fee and calculate shares due\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _vaultProxy The VaultProxy of the fund\n    /// @return settlementType_ The type of settlement\n    /// @return (unused) The payer of shares due\n    /// @return sharesDue_ The amount of shares due\n    function settle(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook,\n        bytes calldata,\n        uint256\n    )\n        external\n        override\n        onlyFeeManager\n        returns (\n            IFeeManager.SettlementType settlementType_,\n            address,\n            uint256 sharesDue_\n        )\n    {\n        FeeInfo storage feeInfo = comptrollerProxyToFeeInfo[_comptrollerProxy];\n\n        // If this fee was settled in the current block, we can return early\n        uint256 secondsSinceSettlement = block.timestamp.sub(feeInfo.lastSettled);\n        if (secondsSinceSettlement == 0) {\n            return (IFeeManager.SettlementType.None, address(0), 0);\n        }\n\n        // If there are shares issued for the fund, calculate the shares due\n        VaultLib vaultProxyContract = VaultLib(_vaultProxy);\n        uint256 sharesSupply = vaultProxyContract.totalSupply();\n        if (sharesSupply > 0) {\n            // This assumes that all shares in the VaultProxy are shares outstanding,\n            // which is fine for this release. Even if they are not, they are still shares that\n            // are only claimable by the fund owner.\n            uint256 netSharesSupply = sharesSupply.sub(vaultProxyContract.balanceOf(_vaultProxy));\n            if (netSharesSupply > 0) {\n                sharesDue_ = netSharesSupply\n                    .mul(\n                    __rpow(feeInfo.scaledPerSecondRate, secondsSinceSettlement, RATE_SCALE_BASE)\n                        .sub(RATE_SCALE_BASE)\n                )\n                    .div(RATE_SCALE_BASE);\n            }\n        }\n\n        // Must settle even when no shares are due, for the case that settlement is being\n        // done when there are no shares in the fund (i.e. at the first investment, or at the\n        // first investment after all shares have been redeemed)\n        comptrollerProxyToFeeInfo[_comptrollerProxy].lastSettled = block.timestamp;\n        emit Settled(_comptrollerProxy, sharesDue_, secondsSinceSettlement);\n\n        if (sharesDue_ == 0) {\n            return (IFeeManager.SettlementType.None, address(0), 0);\n        }\n\n        return (IFeeManager.SettlementType.Mint, address(0), sharesDue_);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the feeInfo for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy contract of the fund\n    /// @return feeInfo_ The feeInfo\n    function getFeeInfoForFund(address _comptrollerProxy)\n        external\n        view\n        returns (FeeInfo memory feeInfo_)\n    {\n        return comptrollerProxyToFeeInfo[_comptrollerProxy];\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/utils/FeeBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../IFee.sol\";\n\n/// @title FeeBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Abstract base contract for all fees\nabstract contract FeeBase is IFee {\n    address internal immutable FEE_MANAGER;\n\n    modifier onlyFeeManager {\n        require(msg.sender == FEE_MANAGER, \"Only the FeeManger can make this call\");\n        _;\n    }\n\n    constructor(address _feeManager) public {\n        FEE_MANAGER = _feeManager;\n    }\n\n    /// @notice Allows Fee to run logic during fund activation\n    /// @dev Unimplemented by default, may be overrode.\n    function activateForFund(address, address) external virtual override {\n        return;\n    }\n\n    /// @notice Runs payout logic for a fee that utilizes shares outstanding as its settlement type\n    /// @dev Returns false by default, can be overridden by fee\n    function payout(address, address) external virtual override returns (bool) {\n        return false;\n    }\n\n    /// @notice Update fee state after all settlement has occurred during a given fee hook\n    /// @dev Unimplemented by default, can be overridden by fee\n    function update(\n        address,\n        address,\n        IFeeManager.FeeHook,\n        bytes calldata,\n        uint256\n    ) external virtual override {\n        return;\n    }\n\n    /// @notice Helper to parse settlement arguments from encoded data for PreBuyShares fee hook\n    function __decodePreBuySharesSettlementData(bytes memory _settlementData)\n        internal\n        pure\n        returns (\n            address buyer_,\n            uint256 investmentAmount_,\n            uint256 minSharesQuantity_\n        )\n    {\n        return abi.decode(_settlementData, (address, uint256, uint256));\n    }\n\n    /// @notice Helper to parse settlement arguments from encoded data for PreRedeemShares fee hook\n    function __decodePreRedeemSharesSettlementData(bytes memory _settlementData)\n        internal\n        pure\n        returns (address redeemer_, uint256 sharesQuantity_)\n    {\n        return abi.decode(_settlementData, (address, uint256));\n    }\n\n    /// @notice Helper to parse settlement arguments from encoded data for PostBuyShares fee hook\n    function __decodePostBuySharesSettlementData(bytes memory _settlementData)\n        internal\n        pure\n        returns (\n            address buyer_,\n            uint256 investmentAmount_,\n            uint256 sharesBought_\n        )\n    {\n        return abi.decode(_settlementData, (address, uint256, uint256));\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `FEE_MANAGER` variable\n    /// @return feeManager_ The `FEE_MANAGER` variable value\n    function getFeeManager() external view returns (address feeManager_) {\n        return FEE_MANAGER;\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/IFee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./IFeeManager.sol\";\n\n/// @title Fee Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Interface for all fees\ninterface IFee {\n    function activateForFund(address _comptrollerProxy, address _vaultProxy) external;\n\n    function addFundSettings(address _comptrollerProxy, bytes calldata _settingsData) external;\n\n    function identifier() external pure returns (string memory identifier_);\n\n    function implementedHooks()\n        external\n        view\n        returns (\n            IFeeManager.FeeHook[] memory implementedHooksForSettle_,\n            IFeeManager.FeeHook[] memory implementedHooksForUpdate_,\n            bool usesGavOnSettle_,\n            bool usesGavOnUpdate_\n        );\n\n    function payout(address _comptrollerProxy, address _vaultProxy)\n        external\n        returns (bool isPayable_);\n\n    function settle(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook _hook,\n        bytes calldata _settlementData,\n        uint256 _gav\n    )\n        external\n        returns (\n            IFeeManager.SettlementType settlementType_,\n            address payer_,\n            uint256 sharesDue_\n        );\n\n    function update(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook _hook,\n        bytes calldata _settlementData,\n        uint256 _gav\n    ) external;\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/PerformanceFee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/math/SignedSafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../FeeManager.sol\";\nimport \"./utils/FeeBase.sol\";\n\n/// @title PerformanceFee Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A performance-based fee with configurable rate and crystallization period, using\n/// a high watermark\n/// @dev This contract assumes that all shares in the VaultProxy are shares outstanding,\n/// which is fine for this release. Even if they are not, they are still shares that\n/// are only claimable by the fund owner.\ncontract PerformanceFee is FeeBase {\n    using SafeMath for uint256;\n    using SignedSafeMath for int256;\n\n    event ActivatedForFund(address indexed comptrollerProxy, uint256 highWaterMark);\n\n    event FundSettingsAdded(address indexed comptrollerProxy, uint256 rate, uint256 period);\n\n    event LastSharePriceUpdated(\n        address indexed comptrollerProxy,\n        uint256 prevSharePrice,\n        uint256 nextSharePrice\n    );\n\n    event PaidOut(\n        address indexed comptrollerProxy,\n        uint256 prevHighWaterMark,\n        uint256 nextHighWaterMark,\n        uint256 aggregateValueDue\n    );\n\n    event PerformanceUpdated(\n        address indexed comptrollerProxy,\n        uint256 prevAggregateValueDue,\n        uint256 nextAggregateValueDue,\n        int256 sharesOutstandingDiff\n    );\n\n    struct FeeInfo {\n        uint256 rate;\n        uint256 period;\n        uint256 activated;\n        uint256 lastPaid;\n        uint256 highWaterMark;\n        uint256 lastSharePrice;\n        uint256 aggregateValueDue;\n    }\n\n    uint256 private constant RATE_DIVISOR = 10**18;\n    uint256 private constant SHARE_UNIT = 10**18;\n\n    mapping(address => FeeInfo) private comptrollerProxyToFeeInfo;\n\n    constructor(address _feeManager) public FeeBase(_feeManager) {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Activates the fee for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    function activateForFund(address _comptrollerProxy, address) external override onlyFeeManager {\n        FeeInfo storage feeInfo = comptrollerProxyToFeeInfo[_comptrollerProxy];\n\n        // We must not force asset finality, otherwise funds that have Synths as tracked assets\n        // would be susceptible to a DoS attack when attempting to migrate to a release that uses\n        // this fee: an attacker trades a negligible amount of a tracked Synth with the VaultProxy\n        // as the recipient, thus causing `calcGrossShareValue(true)` to fail.\n        (uint256 grossSharePrice, bool sharePriceIsValid) = ComptrollerLib(_comptrollerProxy)\n            .calcGrossShareValue(false);\n        require(sharePriceIsValid, \"activateForFund: Invalid share price\");\n\n        feeInfo.highWaterMark = grossSharePrice;\n        feeInfo.lastSharePrice = grossSharePrice;\n        feeInfo.activated = block.timestamp;\n\n        emit ActivatedForFund(_comptrollerProxy, grossSharePrice);\n    }\n\n    /// @notice Add the initial fee settings for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _settingsData Encoded settings to apply to the policy for the fund\n    /// @dev `highWaterMark`, `lastSharePrice`, and `activated` are set during activation\n    function addFundSettings(address _comptrollerProxy, bytes calldata _settingsData)\n        external\n        override\n        onlyFeeManager\n    {\n        (uint256 feeRate, uint256 feePeriod) = abi.decode(_settingsData, (uint256, uint256));\n        require(feeRate > 0, \"addFundSettings: feeRate must be greater than 0\");\n        require(feePeriod > 0, \"addFundSettings: feePeriod must be greater than 0\");\n\n        comptrollerProxyToFeeInfo[_comptrollerProxy] = FeeInfo({\n            rate: feeRate,\n            period: feePeriod,\n            activated: 0,\n            lastPaid: 0,\n            highWaterMark: 0,\n            lastSharePrice: 0,\n            aggregateValueDue: 0\n        });\n\n        emit FundSettingsAdded(_comptrollerProxy, feeRate, feePeriod);\n    }\n\n    /// @notice Provides a constant string identifier for a fee\n    /// @return identifier_ The identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"PERFORMANCE\";\n    }\n\n    /// @notice Gets the hooks that are implemented by the fee\n    /// @return implementedHooksForSettle_ The hooks during which settle() is implemented\n    /// @return implementedHooksForUpdate_ The hooks during which update() is implemented\n    /// @return usesGavOnSettle_ True if GAV is used during the settle() implementation\n    /// @return usesGavOnUpdate_ True if GAV is used during the update() implementation\n    /// @dev Used only during fee registration\n    function implementedHooks()\n        external\n        view\n        override\n        returns (\n            IFeeManager.FeeHook[] memory implementedHooksForSettle_,\n            IFeeManager.FeeHook[] memory implementedHooksForUpdate_,\n            bool usesGavOnSettle_,\n            bool usesGavOnUpdate_\n        )\n    {\n        implementedHooksForSettle_ = new IFeeManager.FeeHook[](3);\n        implementedHooksForSettle_[0] = IFeeManager.FeeHook.Continuous;\n        implementedHooksForSettle_[1] = IFeeManager.FeeHook.BuySharesSetup;\n        implementedHooksForSettle_[2] = IFeeManager.FeeHook.PreRedeemShares;\n\n        implementedHooksForUpdate_ = new IFeeManager.FeeHook[](3);\n        implementedHooksForUpdate_[0] = IFeeManager.FeeHook.Continuous;\n        implementedHooksForUpdate_[1] = IFeeManager.FeeHook.BuySharesCompleted;\n        implementedHooksForUpdate_[2] = IFeeManager.FeeHook.PreRedeemShares;\n\n        return (implementedHooksForSettle_, implementedHooksForUpdate_, true, true);\n    }\n\n    /// @notice Checks whether the shares outstanding for the fee can be paid out, and updates\n    /// the info for the fee's last payout\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return isPayable_ True if shares outstanding can be paid out\n    function payout(address _comptrollerProxy, address)\n        external\n        override\n        onlyFeeManager\n        returns (bool isPayable_)\n    {\n        if (!payoutAllowed(_comptrollerProxy)) {\n            return false;\n        }\n\n        FeeInfo storage feeInfo = comptrollerProxyToFeeInfo[_comptrollerProxy];\n        feeInfo.lastPaid = block.timestamp;\n\n        uint256 prevHighWaterMark = feeInfo.highWaterMark;\n        uint256 nextHighWaterMark = __calcUint256Max(feeInfo.lastSharePrice, prevHighWaterMark);\n        uint256 prevAggregateValueDue = feeInfo.aggregateValueDue;\n\n        // Update state as necessary\n        if (prevAggregateValueDue > 0) {\n            feeInfo.aggregateValueDue = 0;\n        }\n        if (nextHighWaterMark > prevHighWaterMark) {\n            feeInfo.highWaterMark = nextHighWaterMark;\n        }\n\n        emit PaidOut(\n            _comptrollerProxy,\n            prevHighWaterMark,\n            nextHighWaterMark,\n            prevAggregateValueDue\n        );\n\n        return true;\n    }\n\n    /// @notice Settles the fee and calculates shares due\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _vaultProxy The VaultProxy of the fund\n    /// @param _gav The GAV of the fund\n    /// @return settlementType_ The type of settlement\n    /// @return (unused) The payer of shares due\n    /// @return sharesDue_ The amount of shares due\n    function settle(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook,\n        bytes calldata,\n        uint256 _gav\n    )\n        external\n        override\n        onlyFeeManager\n        returns (\n            IFeeManager.SettlementType settlementType_,\n            address,\n            uint256 sharesDue_\n        )\n    {\n        if (_gav == 0) {\n            return (IFeeManager.SettlementType.None, address(0), 0);\n        }\n\n        int256 settlementSharesDue = __settleAndUpdatePerformance(\n            _comptrollerProxy,\n            _vaultProxy,\n            _gav\n        );\n        if (settlementSharesDue == 0) {\n            return (IFeeManager.SettlementType.None, address(0), 0);\n        } else if (settlementSharesDue > 0) {\n            // Settle by minting shares outstanding for custody\n            return (\n                IFeeManager.SettlementType.MintSharesOutstanding,\n                address(0),\n                uint256(settlementSharesDue)\n            );\n        } else {\n            // Settle by burning from shares outstanding\n            return (\n                IFeeManager.SettlementType.BurnSharesOutstanding,\n                address(0),\n                uint256(-settlementSharesDue)\n            );\n        }\n    }\n\n    /// @notice Updates the fee state after all fees have finished settle()\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _vaultProxy The VaultProxy of the fund\n    /// @param _hook The FeeHook being executed\n    /// @param _settlementData Encoded args to use in calculating the settlement\n    /// @param _gav The GAV of the fund\n    function update(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook _hook,\n        bytes calldata _settlementData,\n        uint256 _gav\n    ) external override onlyFeeManager {\n        uint256 prevSharePrice = comptrollerProxyToFeeInfo[_comptrollerProxy].lastSharePrice;\n        uint256 nextSharePrice = __calcNextSharePrice(\n            _comptrollerProxy,\n            _vaultProxy,\n            _hook,\n            _settlementData,\n            _gav\n        );\n\n        if (nextSharePrice == prevSharePrice) {\n            return;\n        }\n\n        comptrollerProxyToFeeInfo[_comptrollerProxy].lastSharePrice = nextSharePrice;\n\n        emit LastSharePriceUpdated(_comptrollerProxy, prevSharePrice, nextSharePrice);\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Checks whether the shares outstanding can be paid out\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return payoutAllowed_ True if the fee payment is due\n    /// @dev Payout is allowed if fees have not yet been settled in a crystallization period,\n    /// and at least 1 crystallization period has passed since activation\n    function payoutAllowed(address _comptrollerProxy) public view returns (bool payoutAllowed_) {\n        FeeInfo memory feeInfo = comptrollerProxyToFeeInfo[_comptrollerProxy];\n        uint256 period = feeInfo.period;\n\n        uint256 timeSinceActivated = block.timestamp.sub(feeInfo.activated);\n\n        // Check if at least 1 crystallization period has passed since activation\n        if (timeSinceActivated < period) {\n            return false;\n        }\n\n        // Check that a full crystallization period has passed since the last payout\n        uint256 timeSincePeriodStart = timeSinceActivated % period;\n        uint256 periodStart = block.timestamp.sub(timeSincePeriodStart);\n        return feeInfo.lastPaid < periodStart;\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to calculate the aggregated value accumulated to a fund since the last\n    /// settlement (happening at investment/redemption)\n    /// Validated:\n    /// _netSharesSupply > 0\n    /// _sharePriceWithoutPerformance != _prevSharePrice\n    function __calcAggregateValueDue(\n        uint256 _netSharesSupply,\n        uint256 _sharePriceWithoutPerformance,\n        uint256 _prevSharePrice,\n        uint256 _prevAggregateValueDue,\n        uint256 _feeRate,\n        uint256 _highWaterMark\n    ) private pure returns (uint256) {\n        int256 superHWMValueSinceLastSettled = (\n            int256(__calcUint256Max(_highWaterMark, _sharePriceWithoutPerformance)).sub(\n                int256(__calcUint256Max(_highWaterMark, _prevSharePrice))\n            )\n        )\n            .mul(int256(_netSharesSupply))\n            .div(int256(SHARE_UNIT));\n\n        int256 valueDueSinceLastSettled = superHWMValueSinceLastSettled.mul(int256(_feeRate)).div(\n            int256(RATE_DIVISOR)\n        );\n\n        return\n            uint256(\n                __calcInt256Max(0, int256(_prevAggregateValueDue).add(valueDueSinceLastSettled))\n            );\n    }\n\n    /// @dev Helper to calculate the max of two int values\n    function __calcInt256Max(int256 _a, int256 _b) private pure returns (int256) {\n        if (_a >= _b) {\n            return _a;\n        }\n\n        return _b;\n    }\n\n    /// @dev Helper to calculate the next `lastSharePrice` value\n    function __calcNextSharePrice(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        IFeeManager.FeeHook _hook,\n        bytes memory _settlementData,\n        uint256 _gav\n    ) private view returns (uint256 nextSharePrice_) {\n        uint256 denominationAssetUnit = 10 **\n            uint256(ERC20(ComptrollerLib(_comptrollerProxy).getDenominationAsset()).decimals());\n        if (_gav == 0) {\n            return denominationAssetUnit;\n        }\n\n        // Get shares outstanding via VaultProxy balance and calc shares supply to get net shares supply\n        ERC20 vaultProxyContract = ERC20(_vaultProxy);\n        uint256 totalSharesSupply = vaultProxyContract.totalSupply();\n        uint256 nextNetSharesSupply = totalSharesSupply.sub(\n            vaultProxyContract.balanceOf(_vaultProxy)\n        );\n        if (nextNetSharesSupply == 0) {\n            return denominationAssetUnit;\n        }\n\n        uint256 nextGav = _gav;\n\n        // For both Continuous and BuySharesCompleted hooks, _gav and shares supply will not change,\n        // we only need additional calculations for PreRedeemShares\n        if (_hook == IFeeManager.FeeHook.PreRedeemShares) {\n            (, uint256 sharesDecrease) = __decodePreRedeemSharesSettlementData(_settlementData);\n\n            // Shares have not yet been burned\n            nextNetSharesSupply = nextNetSharesSupply.sub(sharesDecrease);\n            if (nextNetSharesSupply == 0) {\n                return denominationAssetUnit;\n            }\n\n            // Assets have not yet been withdrawn\n            uint256 gavDecrease = sharesDecrease\n                .mul(_gav)\n                .mul(SHARE_UNIT)\n                .div(totalSharesSupply)\n                .div(denominationAssetUnit);\n\n            nextGav = nextGav.sub(gavDecrease);\n            if (nextGav == 0) {\n                return denominationAssetUnit;\n            }\n        }\n\n        return nextGav.mul(SHARE_UNIT).div(nextNetSharesSupply);\n    }\n\n    /// @dev Helper to calculate the performance metrics for a fund.\n    /// Validated:\n    /// _totalSharesSupply > 0\n    /// _gav > 0\n    /// _totalSharesSupply != _totalSharesOutstanding\n    function __calcPerformance(\n        address _comptrollerProxy,\n        uint256 _totalSharesSupply,\n        uint256 _totalSharesOutstanding,\n        uint256 _prevAggregateValueDue,\n        FeeInfo memory feeInfo,\n        uint256 _gav\n    ) private view returns (uint256 nextAggregateValueDue_, int256 sharesDue_) {\n        // Use the 'shares supply net shares outstanding' for performance calcs.\n        // Cannot be 0, as _totalSharesSupply != _totalSharesOutstanding\n        uint256 netSharesSupply = _totalSharesSupply.sub(_totalSharesOutstanding);\n        uint256 sharePriceWithoutPerformance = _gav.mul(SHARE_UNIT).div(netSharesSupply);\n\n        // If gross share price has not changed, can exit early\n        uint256 prevSharePrice = feeInfo.lastSharePrice;\n        if (sharePriceWithoutPerformance == prevSharePrice) {\n            return (_prevAggregateValueDue, 0);\n        }\n\n        nextAggregateValueDue_ = __calcAggregateValueDue(\n            netSharesSupply,\n            sharePriceWithoutPerformance,\n            prevSharePrice,\n            _prevAggregateValueDue,\n            feeInfo.rate,\n            feeInfo.highWaterMark\n        );\n\n        sharesDue_ = __calcSharesDue(\n            _comptrollerProxy,\n            netSharesSupply,\n            _gav,\n            nextAggregateValueDue_\n        );\n\n        return (nextAggregateValueDue_, sharesDue_);\n    }\n\n    /// @dev Helper to calculate sharesDue during settlement.\n    /// Validated:\n    /// _netSharesSupply > 0\n    /// _gav > 0\n    function __calcSharesDue(\n        address _comptrollerProxy,\n        uint256 _netSharesSupply,\n        uint256 _gav,\n        uint256 _nextAggregateValueDue\n    ) private view returns (int256 sharesDue_) {\n        // If _nextAggregateValueDue > _gav, then no shares can be created.\n        // This is a known limitation of the model, which is only reached for unrealistically\n        // high performance fee rates (> 100%). A revert is allowed in such a case.\n        uint256 sharesDueForAggregateValueDue = _nextAggregateValueDue.mul(_netSharesSupply).div(\n            _gav.sub(_nextAggregateValueDue)\n        );\n\n        // Shares due is the +/- diff or the total shares outstanding already minted\n        return\n            int256(sharesDueForAggregateValueDue).sub(\n                int256(\n                    FeeManager(FEE_MANAGER).getFeeSharesOutstandingForFund(\n                        _comptrollerProxy,\n                        address(this)\n                    )\n                )\n            );\n    }\n\n    /// @dev Helper to calculate the max of two uint values\n    function __calcUint256Max(uint256 _a, uint256 _b) private pure returns (uint256) {\n        if (_a >= _b) {\n            return _a;\n        }\n\n        return _b;\n    }\n\n    /// @dev Helper to settle the fee and update performance state.\n    /// Validated:\n    /// _gav > 0\n    function __settleAndUpdatePerformance(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        uint256 _gav\n    ) private returns (int256 sharesDue_) {\n        ERC20 sharesTokenContract = ERC20(_vaultProxy);\n\n        uint256 totalSharesSupply = sharesTokenContract.totalSupply();\n        if (totalSharesSupply == 0) {\n            return 0;\n        }\n\n        uint256 totalSharesOutstanding = sharesTokenContract.balanceOf(_vaultProxy);\n        if (totalSharesOutstanding == totalSharesSupply) {\n            return 0;\n        }\n\n        FeeInfo storage feeInfo = comptrollerProxyToFeeInfo[_comptrollerProxy];\n        uint256 prevAggregateValueDue = feeInfo.aggregateValueDue;\n\n        uint256 nextAggregateValueDue;\n        (nextAggregateValueDue, sharesDue_) = __calcPerformance(\n            _comptrollerProxy,\n            totalSharesSupply,\n            totalSharesOutstanding,\n            prevAggregateValueDue,\n            feeInfo,\n            _gav\n        );\n        if (nextAggregateValueDue == prevAggregateValueDue) {\n            return 0;\n        }\n\n        // Update fee state\n        feeInfo.aggregateValueDue = nextAggregateValueDue;\n\n        emit PerformanceUpdated(\n            _comptrollerProxy,\n            prevAggregateValueDue,\n            nextAggregateValueDue,\n            sharesDue_\n        );\n\n        return sharesDue_;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the feeInfo for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy contract of the fund\n    /// @return feeInfo_ The feeInfo\n    function getFeeInfoForFund(address _comptrollerProxy)\n        external\n        view\n        returns (FeeInfo memory feeInfo_)\n    {\n        return comptrollerProxyToFeeInfo[_comptrollerProxy];\n    }\n}\n"
      },
      "@openzeppelin/contracts/math/SignedSafeMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n    int256 constant private _INT256_MIN = -2**255;\n\n    /**\n     * @dev Returns the multiplication of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(int256 a, int256 b) internal pure returns (int256) {\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) {\n            return 0;\n        }\n\n        require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n        int256 c = a * b;\n        require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two signed integers. Reverts 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(int256 a, int256 b) internal pure returns (int256) {\n        require(b != 0, \"SignedSafeMath: division by zero\");\n        require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n        int256 c = a / b;\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(int256 a, int256 b) internal pure returns (int256) {\n        int256 c = a - b;\n        require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the addition of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(int256 a, int256 b) internal pure returns (int256) {\n        int256 c = a + b;\n        require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n        return c;\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/FeeManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/EnumerableSet.sol\";\nimport \"../../core/fund/comptroller/IComptroller.sol\";\nimport \"../../core/fund/vault/IVault.sol\";\nimport \"../../utils/AddressArrayLib.sol\";\nimport \"../utils/ExtensionBase.sol\";\nimport \"../utils/FundDeployerOwnerMixin.sol\";\nimport \"../utils/PermissionedVaultActionMixin.sol\";\nimport \"./IFee.sol\";\nimport \"./IFeeManager.sol\";\n\n/// @title FeeManager Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Manages fees for funds\ncontract FeeManager is\n    IFeeManager,\n    ExtensionBase,\n    FundDeployerOwnerMixin,\n    PermissionedVaultActionMixin\n{\n    using AddressArrayLib for address[];\n    using EnumerableSet for EnumerableSet.AddressSet;\n    using SafeMath for uint256;\n\n    event AllSharesOutstandingForcePaidForFund(\n        address indexed comptrollerProxy,\n        address payee,\n        uint256 sharesDue\n    );\n\n    event FeeDeregistered(address indexed fee, string indexed identifier);\n\n    event FeeEnabledForFund(\n        address indexed comptrollerProxy,\n        address indexed fee,\n        bytes settingsData\n    );\n\n    event FeeRegistered(\n        address indexed fee,\n        string indexed identifier,\n        FeeHook[] implementedHooksForSettle,\n        FeeHook[] implementedHooksForUpdate,\n        bool usesGavOnSettle,\n        bool usesGavOnUpdate\n    );\n\n    event FeeSettledForFund(\n        address indexed comptrollerProxy,\n        address indexed fee,\n        SettlementType indexed settlementType,\n        address payer,\n        address payee,\n        uint256 sharesDue\n    );\n\n    event SharesOutstandingPaidForFund(\n        address indexed comptrollerProxy,\n        address indexed fee,\n        uint256 sharesDue\n    );\n\n    event FeesRecipientSetForFund(\n        address indexed comptrollerProxy,\n        address prevFeesRecipient,\n        address nextFeesRecipient\n    );\n\n    EnumerableSet.AddressSet private registeredFees;\n    mapping(address => bool) private feeToUsesGavOnSettle;\n    mapping(address => bool) private feeToUsesGavOnUpdate;\n    mapping(address => mapping(FeeHook => bool)) private feeToHookToImplementsSettle;\n    mapping(address => mapping(FeeHook => bool)) private feeToHookToImplementsUpdate;\n\n    mapping(address => address[]) private comptrollerProxyToFees;\n    mapping(address => mapping(address => uint256))\n        private comptrollerProxyToFeeToSharesOutstanding;\n\n    constructor(address _fundDeployer) public FundDeployerOwnerMixin(_fundDeployer) {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Activate already-configured fees for use in the calling fund\n    function activateForFund(bool) external override {\n        address vaultProxy = __setValidatedVaultProxy(msg.sender);\n\n        address[] memory enabledFees = comptrollerProxyToFees[msg.sender];\n        for (uint256 i; i < enabledFees.length; i++) {\n            IFee(enabledFees[i]).activateForFund(msg.sender, vaultProxy);\n        }\n    }\n\n    /// @notice Deactivate fees for a fund\n    /// @dev msg.sender is validated during __invokeHook()\n    function deactivateForFund() external override {\n        // Settle continuous fees one last time, but without calling Fee.update()\n        __invokeHook(msg.sender, IFeeManager.FeeHook.Continuous, \"\", 0, false);\n\n        // Force payout of remaining shares outstanding\n        __forcePayoutAllSharesOutstanding(msg.sender);\n\n        // Clean up storage\n        __deleteFundStorage(msg.sender);\n    }\n\n    /// @notice Receives a dispatched `callOnExtension` from a fund's ComptrollerProxy\n    /// @param _actionId An ID representing the desired action\n    /// @param _callArgs Encoded arguments specific to the _actionId\n    /// @dev This is the only way to call a function on this contract that updates VaultProxy state.\n    /// For both of these actions, any caller is allowed, so we don't use the caller param.\n    function receiveCallFromComptroller(\n        address,\n        uint256 _actionId,\n        bytes calldata _callArgs\n    ) external override {\n        if (_actionId == 0) {\n            // Settle and update all continuous fees\n            __invokeHook(msg.sender, IFeeManager.FeeHook.Continuous, \"\", 0, true);\n        } else if (_actionId == 1) {\n            __payoutSharesOutstandingForFees(msg.sender, _callArgs);\n        } else {\n            revert(\"receiveCallFromComptroller: Invalid _actionId\");\n        }\n    }\n\n    /// @notice Enable and configure fees for use in the calling fund\n    /// @param _configData Encoded config data\n    /// @dev Caller is expected to be a valid ComptrollerProxy, but there isn't a need to validate.\n    /// The order of `fees` determines the order in which fees of the same FeeHook will be applied.\n    /// It is recommended to run ManagementFee before PerformanceFee in order to achieve precise\n    /// PerformanceFee calcs.\n    function setConfigForFund(bytes calldata _configData) external override {\n        (address[] memory fees, bytes[] memory settingsData) = abi.decode(\n            _configData,\n            (address[], bytes[])\n        );\n\n        // Sanity checks\n        require(\n            fees.length == settingsData.length,\n            \"setConfigForFund: fees and settingsData array lengths unequal\"\n        );\n        require(fees.isUniqueSet(), \"setConfigForFund: fees cannot include duplicates\");\n\n        // Enable each fee with settings\n        for (uint256 i; i < fees.length; i++) {\n            require(isRegisteredFee(fees[i]), \"setConfigForFund: Fee is not registered\");\n\n            // Set fund config on fee\n            IFee(fees[i]).addFundSettings(msg.sender, settingsData[i]);\n\n            // Enable fee for fund\n            comptrollerProxyToFees[msg.sender].push(fees[i]);\n\n            emit FeeEnabledForFund(msg.sender, fees[i], settingsData[i]);\n        }\n    }\n\n    /// @notice Allows all fees for a particular FeeHook to implement settle() and update() logic\n    /// @param _hook The FeeHook to invoke\n    /// @param _settlementData The encoded settlement parameters specific to the FeeHook\n    /// @param _gav The GAV for a fund if known in the invocating code, otherwise 0\n    function invokeHook(\n        FeeHook _hook,\n        bytes calldata _settlementData,\n        uint256 _gav\n    ) external override {\n        __invokeHook(msg.sender, _hook, _settlementData, _gav, true);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to destroy local storage to get gas refund,\n    /// and to prevent further calls to fee manager\n    function __deleteFundStorage(address _comptrollerProxy) private {\n        delete comptrollerProxyToFees[_comptrollerProxy];\n        delete comptrollerProxyToVaultProxy[_comptrollerProxy];\n    }\n\n    /// @dev Helper to force the payout of shares outstanding across all fees.\n    /// For the current release, all shares in the VaultProxy are assumed to be\n    /// shares outstanding from fees. If not, then they were sent there by mistake\n    /// and are otherwise unrecoverable. We can therefore take the VaultProxy's\n    /// shares balance as the totalSharesOutstanding to payout to the fund owner.\n    function __forcePayoutAllSharesOutstanding(address _comptrollerProxy) private {\n        address vaultProxy = getVaultProxyForFund(_comptrollerProxy);\n\n        uint256 totalSharesOutstanding = ERC20(vaultProxy).balanceOf(vaultProxy);\n        if (totalSharesOutstanding == 0) {\n            return;\n        }\n\n        // Destroy any shares outstanding storage\n        address[] memory fees = comptrollerProxyToFees[_comptrollerProxy];\n        for (uint256 i; i < fees.length; i++) {\n            delete comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][fees[i]];\n        }\n\n        // Distribute all shares outstanding to the fees recipient\n        address payee = IVault(vaultProxy).getOwner();\n        __transferShares(_comptrollerProxy, vaultProxy, payee, totalSharesOutstanding);\n\n        emit AllSharesOutstandingForcePaidForFund(\n            _comptrollerProxy,\n            payee,\n            totalSharesOutstanding\n        );\n    }\n\n    /// @dev Helper to get the canonical value of GAV if not yet set and required by fee\n    function __getGavAsNecessary(\n        address _comptrollerProxy,\n        address _fee,\n        uint256 _gavOrZero\n    ) private returns (uint256 gav_) {\n        if (_gavOrZero == 0 && feeUsesGavOnUpdate(_fee)) {\n            // Assumes that any fee that requires GAV would need to revert if invalid or not final\n            bool gavIsValid;\n            (gav_, gavIsValid) = IComptroller(_comptrollerProxy).calcGav(true);\n            require(gavIsValid, \"__getGavAsNecessary: Invalid GAV\");\n        } else {\n            gav_ = _gavOrZero;\n        }\n\n        return gav_;\n    }\n\n    /// @dev Helper to run settle() on all enabled fees for a fund that implement a given hook, and then to\n    /// optionally run update() on the same fees. This order allows fees an opportunity to update\n    /// their local state after all VaultProxy state transitions (i.e., minting, burning,\n    /// transferring shares) have finished. To optimize for the expensive operation of calculating\n    /// GAV, once one fee requires GAV, we recycle that `gav` value for subsequent fees.\n    /// Assumes that _gav is either 0 or has already been validated.\n    function __invokeHook(\n        address _comptrollerProxy,\n        FeeHook _hook,\n        bytes memory _settlementData,\n        uint256 _gavOrZero,\n        bool _updateFees\n    ) private {\n        address[] memory fees = comptrollerProxyToFees[_comptrollerProxy];\n        if (fees.length == 0) {\n            return;\n        }\n\n        address vaultProxy = getVaultProxyForFund(_comptrollerProxy);\n\n        // This check isn't strictly necessary, but its cost is insignificant,\n        // and helps to preserve data integrity.\n        require(vaultProxy != address(0), \"__invokeHook: Fund is not active\");\n\n        // First, allow all fees to implement settle()\n        uint256 gav = __settleFees(\n            _comptrollerProxy,\n            vaultProxy,\n            fees,\n            _hook,\n            _settlementData,\n            _gavOrZero\n        );\n\n        // Second, allow fees to implement update()\n        // This function does not allow any further altering of VaultProxy state\n        // (i.e., burning, minting, or transferring shares)\n        if (_updateFees) {\n            __updateFees(_comptrollerProxy, vaultProxy, fees, _hook, _settlementData, gav);\n        }\n    }\n\n    /// @dev Helper to payout the shares outstanding for the specified fees.\n    /// Does not call settle() on fees.\n    /// Only callable via ComptrollerProxy.callOnExtension().\n    function __payoutSharesOutstandingForFees(address _comptrollerProxy, bytes memory _callArgs)\n        private\n    {\n        address[] memory fees = abi.decode(_callArgs, (address[]));\n        address vaultProxy = getVaultProxyForFund(msg.sender);\n\n        uint256 sharesOutstandingDue;\n        for (uint256 i; i < fees.length; i++) {\n            if (!IFee(fees[i]).payout(_comptrollerProxy, vaultProxy)) {\n                continue;\n            }\n\n\n                uint256 sharesOutstandingForFee\n             = comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][fees[i]];\n            if (sharesOutstandingForFee == 0) {\n                continue;\n            }\n\n            sharesOutstandingDue = sharesOutstandingDue.add(sharesOutstandingForFee);\n\n            // Delete shares outstanding and distribute from VaultProxy to the fees recipient\n            comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][fees[i]] = 0;\n\n            emit SharesOutstandingPaidForFund(_comptrollerProxy, fees[i], sharesOutstandingForFee);\n        }\n\n        if (sharesOutstandingDue > 0) {\n            __transferShares(\n                _comptrollerProxy,\n                vaultProxy,\n                IVault(vaultProxy).getOwner(),\n                sharesOutstandingDue\n            );\n        }\n    }\n\n    /// @dev Helper to settle a fee\n    function __settleFee(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        address _fee,\n        FeeHook _hook,\n        bytes memory _settlementData,\n        uint256 _gav\n    ) private {\n        (SettlementType settlementType, address payer, uint256 sharesDue) = IFee(_fee).settle(\n            _comptrollerProxy,\n            _vaultProxy,\n            _hook,\n            _settlementData,\n            _gav\n        );\n        if (settlementType == SettlementType.None) {\n            return;\n        }\n\n        address payee;\n        if (settlementType == SettlementType.Direct) {\n            payee = IVault(_vaultProxy).getOwner();\n            __transferShares(_comptrollerProxy, payer, payee, sharesDue);\n        } else if (settlementType == SettlementType.Mint) {\n            payee = IVault(_vaultProxy).getOwner();\n            __mintShares(_comptrollerProxy, payee, sharesDue);\n        } else if (settlementType == SettlementType.Burn) {\n            __burnShares(_comptrollerProxy, payer, sharesDue);\n        } else if (settlementType == SettlementType.MintSharesOutstanding) {\n            comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][_fee] = comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][_fee]\n                .add(sharesDue);\n\n            payee = _vaultProxy;\n            __mintShares(_comptrollerProxy, payee, sharesDue);\n        } else if (settlementType == SettlementType.BurnSharesOutstanding) {\n            comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][_fee] = comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][_fee]\n                .sub(sharesDue);\n\n            payer = _vaultProxy;\n            __burnShares(_comptrollerProxy, payer, sharesDue);\n        } else {\n            revert(\"__settleFee: Invalid SettlementType\");\n        }\n\n        emit FeeSettledForFund(_comptrollerProxy, _fee, settlementType, payer, payee, sharesDue);\n    }\n\n    /// @dev Helper to settle fees that implement a given fee hook\n    function __settleFees(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        address[] memory _fees,\n        FeeHook _hook,\n        bytes memory _settlementData,\n        uint256 _gavOrZero\n    ) private returns (uint256 gav_) {\n        gav_ = _gavOrZero;\n\n        for (uint256 i; i < _fees.length; i++) {\n            if (!feeSettlesOnHook(_fees[i], _hook)) {\n                continue;\n            }\n\n            gav_ = __getGavAsNecessary(_comptrollerProxy, _fees[i], gav_);\n\n            __settleFee(_comptrollerProxy, _vaultProxy, _fees[i], _hook, _settlementData, gav_);\n        }\n\n        return gav_;\n    }\n\n    /// @dev Helper to update fees that implement a given fee hook\n    function __updateFees(\n        address _comptrollerProxy,\n        address _vaultProxy,\n        address[] memory _fees,\n        FeeHook _hook,\n        bytes memory _settlementData,\n        uint256 _gavOrZero\n    ) private {\n        uint256 gav = _gavOrZero;\n\n        for (uint256 i; i < _fees.length; i++) {\n            if (!feeUpdatesOnHook(_fees[i], _hook)) {\n                continue;\n            }\n\n            gav = __getGavAsNecessary(_comptrollerProxy, _fees[i], gav);\n\n            IFee(_fees[i]).update(_comptrollerProxy, _vaultProxy, _hook, _settlementData, gav);\n        }\n    }\n\n    ///////////////////\n    // FEES REGISTRY //\n    ///////////////////\n\n    /// @notice Remove fees from the list of registered fees\n    /// @param _fees Addresses of fees to be deregistered\n    function deregisterFees(address[] calldata _fees) external onlyFundDeployerOwner {\n        require(_fees.length > 0, \"deregisterFees: _fees cannot be empty\");\n\n        for (uint256 i; i < _fees.length; i++) {\n            require(isRegisteredFee(_fees[i]), \"deregisterFees: fee is not registered\");\n\n            registeredFees.remove(_fees[i]);\n\n            emit FeeDeregistered(_fees[i], IFee(_fees[i]).identifier());\n        }\n    }\n\n    /// @notice Add fees to the list of registered fees\n    /// @param _fees Addresses of fees to be registered\n    /// @dev Stores the hooks that a fee implements and whether each implementation uses GAV,\n    /// which fronts the gas for calls to check if a hook is implemented, and guarantees\n    /// that these hook implementation return values do not change post-registration.\n    function registerFees(address[] calldata _fees) external onlyFundDeployerOwner {\n        require(_fees.length > 0, \"registerFees: _fees cannot be empty\");\n\n        for (uint256 i; i < _fees.length; i++) {\n            require(!isRegisteredFee(_fees[i]), \"registerFees: fee already registered\");\n\n            registeredFees.add(_fees[i]);\n\n            IFee feeContract = IFee(_fees[i]);\n            (\n                FeeHook[] memory implementedHooksForSettle,\n                FeeHook[] memory implementedHooksForUpdate,\n                bool usesGavOnSettle,\n                bool usesGavOnUpdate\n            ) = feeContract.implementedHooks();\n\n            // Stores the hooks for which each fee implements settle() and update()\n            for (uint256 j; j < implementedHooksForSettle.length; j++) {\n                feeToHookToImplementsSettle[_fees[i]][implementedHooksForSettle[j]] = true;\n            }\n            for (uint256 j; j < implementedHooksForUpdate.length; j++) {\n                feeToHookToImplementsUpdate[_fees[i]][implementedHooksForUpdate[j]] = true;\n            }\n\n            // Stores whether each fee requires GAV during its implementations for settle() and update()\n            if (usesGavOnSettle) {\n                feeToUsesGavOnSettle[_fees[i]] = true;\n            }\n            if (usesGavOnUpdate) {\n                feeToUsesGavOnUpdate[_fees[i]] = true;\n            }\n\n            emit FeeRegistered(\n                _fees[i],\n                feeContract.identifier(),\n                implementedHooksForSettle,\n                implementedHooksForUpdate,\n                usesGavOnSettle,\n                usesGavOnUpdate\n            );\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Get a list of enabled fees for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return enabledFees_ An array of enabled fee addresses\n    function getEnabledFeesForFund(address _comptrollerProxy)\n        external\n        view\n        returns (address[] memory enabledFees_)\n    {\n        return comptrollerProxyToFees[_comptrollerProxy];\n    }\n\n    /// @notice Get the amount of shares outstanding for a particular fee for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _fee The fee address\n    /// @return sharesOutstanding_ The amount of shares outstanding\n    function getFeeSharesOutstandingForFund(address _comptrollerProxy, address _fee)\n        external\n        view\n        returns (uint256 sharesOutstanding_)\n    {\n        return comptrollerProxyToFeeToSharesOutstanding[_comptrollerProxy][_fee];\n    }\n\n    /// @notice Get all registered fees\n    /// @return registeredFees_ A list of all registered fee addresses\n    function getRegisteredFees() external view returns (address[] memory registeredFees_) {\n        registeredFees_ = new address[](registeredFees.length());\n        for (uint256 i; i < registeredFees_.length; i++) {\n            registeredFees_[i] = registeredFees.at(i);\n        }\n\n        return registeredFees_;\n    }\n\n    /// @notice Checks if a fee implements settle() on a particular hook\n    /// @param _fee The address of the fee to check\n    /// @param _hook The FeeHook to check\n    /// @return settlesOnHook_ True if the fee settles on the given hook\n    function feeSettlesOnHook(address _fee, FeeHook _hook)\n        public\n        view\n        returns (bool settlesOnHook_)\n    {\n        return feeToHookToImplementsSettle[_fee][_hook];\n    }\n\n    /// @notice Checks if a fee implements update() on a particular hook\n    /// @param _fee The address of the fee to check\n    /// @param _hook The FeeHook to check\n    /// @return updatesOnHook_ True if the fee updates on the given hook\n    function feeUpdatesOnHook(address _fee, FeeHook _hook)\n        public\n        view\n        returns (bool updatesOnHook_)\n    {\n        return feeToHookToImplementsUpdate[_fee][_hook];\n    }\n\n    /// @notice Checks if a fee uses GAV in its settle() implementation\n    /// @param _fee The address of the fee to check\n    /// @return usesGav_ True if the fee uses GAV during settle() implementation\n    function feeUsesGavOnSettle(address _fee) public view returns (bool usesGav_) {\n        return feeToUsesGavOnSettle[_fee];\n    }\n\n    /// @notice Checks if a fee uses GAV in its update() implementation\n    /// @param _fee The address of the fee to check\n    /// @return usesGav_ True if the fee uses GAV during update() implementation\n    function feeUsesGavOnUpdate(address _fee) public view returns (bool usesGav_) {\n        return feeToUsesGavOnUpdate[_fee];\n    }\n\n    /// @notice Check whether a fee is registered\n    /// @param _fee The address of the fee to check\n    /// @return isRegisteredFee_ True if the fee is registered\n    function isRegisteredFee(address _fee) public view returns (bool isRegisteredFee_) {\n        return registeredFees.contains(_fee);\n    }\n}\n"
      },
      "contracts/release/extensions/utils/PermissionedVaultActionMixin.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../core/fund/comptroller/IComptroller.sol\";\n\n/// @title PermissionedVaultActionMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract for extensions that can make permissioned vault calls\nabstract contract PermissionedVaultActionMixin {\n    /// @notice Adds a tracked asset to the fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _asset The asset to add\n    function __addTrackedAsset(address _comptrollerProxy, address _asset) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.AddTrackedAsset,\n            abi.encode(_asset)\n        );\n    }\n\n    /// @notice Grants an allowance to a spender to use a fund's asset\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _asset The asset for which to grant an allowance\n    /// @param _target The spender of the allowance\n    /// @param _amount The amount of the allowance\n    function __approveAssetSpender(\n        address _comptrollerProxy,\n        address _asset,\n        address _target,\n        uint256 _amount\n    ) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.ApproveAssetSpender,\n            abi.encode(_asset, _target, _amount)\n        );\n    }\n\n    /// @notice Burns fund shares for a particular account\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _target The account for which to burn shares\n    /// @param _amount The amount of shares to burn\n    function __burnShares(\n        address _comptrollerProxy,\n        address _target,\n        uint256 _amount\n    ) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.BurnShares,\n            abi.encode(_target, _amount)\n        );\n    }\n\n    /// @notice Mints fund shares to a particular account\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _target The account to which to mint shares\n    /// @param _amount The amount of shares to mint\n    function __mintShares(\n        address _comptrollerProxy,\n        address _target,\n        uint256 _amount\n    ) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.MintShares,\n            abi.encode(_target, _amount)\n        );\n    }\n\n    /// @notice Removes a tracked asset from the fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _asset The asset to remove\n    function __removeTrackedAsset(address _comptrollerProxy, address _asset) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.RemoveTrackedAsset,\n            abi.encode(_asset)\n        );\n    }\n\n    /// @notice Transfers fund shares from one account to another\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _from The account from which to transfer shares\n    /// @param _to The account to which to transfer shares\n    /// @param _amount The amount of shares to transfer\n    function __transferShares(\n        address _comptrollerProxy,\n        address _from,\n        address _to,\n        uint256 _amount\n    ) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.TransferShares,\n            abi.encode(_from, _to, _amount)\n        );\n    }\n\n    /// @notice Withdraws an asset from the VaultProxy to a given account\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _asset The asset to withdraw\n    /// @param _target The account to which to withdraw the asset\n    /// @param _amount The amount of asset to withdraw\n    function __withdrawAssetTo(\n        address _comptrollerProxy,\n        address _asset,\n        address _target,\n        uint256 _amount\n    ) internal {\n        IComptroller(_comptrollerProxy).permissionedVaultAction(\n            IComptroller.VaultAction.WithdrawAssetTo,\n            abi.encode(_asset, _target, _amount)\n        );\n    }\n}\n"
      },
      "contracts/release/peripheral/FundActionsWrapper.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../extensions/fee-manager/FeeManager.sol\";\n\n/// @title FundActionsWrapper Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Logic related to funds, not necessary in the core protocol\n/// @dev This contract is currently unaudited, as it does not involve any\n/// exchange in value, and simply wraps other functions for convenience\ncontract FundActionsWrapper {\n    address private immutable FEE_MANAGER;\n\n    constructor(address _feeManager) public {\n        FEE_MANAGER = _feeManager;\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Calculates the net value of 1 unit of shares in the fund's denomination asset\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return netShareValue_ The amount of the denomination asset per share\n    /// @return isValid_ True if the conversion rates to derive the value are all valid\n    /// @dev Accounts for fees outstanding. This is a convenience function for external consumption\n    /// that can be used to determine the cost of purchasing shares at any given point in time.\n    /// It essentially just bundles settling all fees that implement the Continuous hook and then\n    /// looking up the gross share value.\n    function calcNetShareValueForFund(address _comptrollerProxy)\n        external\n        returns (uint256 netShareValue_, bool isValid_)\n    {\n        ComptrollerLib comptrollerProxyContract = ComptrollerLib(_comptrollerProxy);\n        comptrollerProxyContract.callOnExtension(FEE_MANAGER, 0, \"\");\n\n        return comptrollerProxyContract.calcGrossShareValue(false);\n    }\n\n    /// @notice Invokes the Continuous fee hook on all specified fees, and then attempts to payout\n    /// any shares outstanding on those fees\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _fees The fees for which to run these actions\n    /// @dev This is just a wrapper to execute two callOnExtension() actions atomically, in sequence.\n    /// The caller must pass in the fees that they want to run this logic on.\n    function invokeContinuousFeeHookAndPayoutSharesOutstandingForFund(\n        address _comptrollerProxy,\n        address[] calldata _fees\n    ) external {\n        ComptrollerLib comptrollerProxyContract = ComptrollerLib(_comptrollerProxy);\n\n        comptrollerProxyContract.callOnExtension(FEE_MANAGER, 0, \"\");\n        comptrollerProxyContract.callOnExtension(FEE_MANAGER, 1, abi.encode(_fees));\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Gets all fees that implement the `Continuous` fee hook for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return continuousFees_ The fees that implement the `Continuous` fee hook\n    function getContinuousFeesForFund(address _comptrollerProxy)\n        public\n        view\n        returns (address[] memory continuousFees_)\n    {\n        FeeManager feeManagerContract = FeeManager(FEE_MANAGER);\n\n        address[] memory fees = feeManagerContract.getEnabledFeesForFund(_comptrollerProxy);\n\n        // Count the continuous fees\n        uint256 continuousFeesCount;\n        bool[] memory implementsContinuousHook = new bool[](fees.length);\n        for (uint256 i; i < fees.length; i++) {\n            if (feeManagerContract.feeSettlesOnHook(fees[i], IFeeManager.FeeHook.Continuous)) {\n                continuousFeesCount++;\n                implementsContinuousHook[i] = true;\n            }\n        }\n\n        // Return early if no continuous fees\n        if (continuousFeesCount == 0) {\n            return new address[](0);\n        }\n\n        // Create continuous fees array\n        continuousFees_ = new address[](continuousFeesCount);\n        uint256 continuousFeesIndex;\n        for (uint256 i; i < fees.length; i++) {\n            if (implementsContinuousHook[i]) {\n                continuousFees_[continuousFeesIndex] = fees[i];\n                continuousFeesIndex++;\n            }\n        }\n\n        return continuousFees_;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `FEE_MANAGER` variable\n    /// @return feeManager_ The `FEE_MANAGER` variable value\n    function getFeeManager() external view returns (address feeManager_) {\n        return FEE_MANAGER;\n    }\n}\n"
      },
      "contracts/release/peripheral/shares-requestors/AuthUserExecutedSharesRequestorLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport \"../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../../core/fund/vault/VaultLib.sol\";\nimport \"./IAuthUserExecutedSharesRequestor.sol\";\n\n/// @title AuthUserExecutedSharesRequestorLib Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Provides the logic for AuthUserExecutedSharesRequestorProxy instances,\n/// in which shares requests are manually executed by a permissioned user\n/// @dev This will not work with a `denominationAsset` that does not transfer\n/// the exact expected amount or has an elastic supply.\ncontract AuthUserExecutedSharesRequestorLib is IAuthUserExecutedSharesRequestor {\n    using SafeERC20 for ERC20;\n    using SafeMath for uint256;\n\n    event RequestCanceled(\n        address indexed requestOwner,\n        uint256 investmentAmount,\n        uint256 minSharesQuantity\n    );\n\n    event RequestCreated(\n        address indexed requestOwner,\n        uint256 investmentAmount,\n        uint256 minSharesQuantity\n    );\n\n    event RequestExecuted(\n        address indexed caller,\n        address indexed requestOwner,\n        uint256 investmentAmount,\n        uint256 minSharesQuantity\n    );\n\n    event RequestExecutorAdded(address indexed account);\n\n    event RequestExecutorRemoved(address indexed account);\n\n    struct RequestInfo {\n        uint256 investmentAmount;\n        uint256 minSharesQuantity;\n    }\n\n    uint256 private constant CANCELLATION_COOLDOWN_TIMELOCK = 10 minutes;\n\n    address private comptrollerProxy;\n    address private denominationAsset;\n    address private fundOwner;\n\n    mapping(address => RequestInfo) private ownerToRequestInfo;\n    mapping(address => bool) private acctToIsRequestExecutor;\n    mapping(address => uint256) private ownerToLastRequestCancellation;\n\n    modifier onlyFundOwner() {\n        require(msg.sender == fundOwner, \"Only fund owner callable\");\n        _;\n    }\n\n    /// @notice Initializes a proxy instance that uses this library\n    /// @dev Serves as a per-proxy pseudo-constructor\n    function init(address _comptrollerProxy) external override {\n        require(comptrollerProxy == address(0), \"init: Already initialized\");\n\n        comptrollerProxy = _comptrollerProxy;\n\n        // Cache frequently-used values that require external calls\n        ComptrollerLib comptrollerProxyContract = ComptrollerLib(_comptrollerProxy);\n        denominationAsset = comptrollerProxyContract.getDenominationAsset();\n        fundOwner = VaultLib(comptrollerProxyContract.getVaultProxy()).getOwner();\n    }\n\n    /// @notice Cancels the shares request of the caller\n    function cancelRequest() external {\n        RequestInfo memory request = ownerToRequestInfo[msg.sender];\n        require(request.investmentAmount > 0, \"cancelRequest: Request does not exist\");\n\n        // Delete the request, start the cooldown period, and return the investment asset\n        delete ownerToRequestInfo[msg.sender];\n        ownerToLastRequestCancellation[msg.sender] = block.timestamp;\n        ERC20(denominationAsset).safeTransfer(msg.sender, request.investmentAmount);\n\n        emit RequestCanceled(msg.sender, request.investmentAmount, request.minSharesQuantity);\n    }\n\n    /// @notice Creates a shares request for the caller\n    /// @param _investmentAmount The amount of the fund's denomination asset to use to buy shares\n    /// @param _minSharesQuantity The minimum quantity of shares to buy with the _investmentAmount\n    function createRequest(uint256 _investmentAmount, uint256 _minSharesQuantity) external {\n        require(_investmentAmount > 0, \"createRequest: _investmentAmount must be > 0\");\n        require(\n            ownerToRequestInfo[msg.sender].investmentAmount == 0,\n            \"createRequest: The request owner can only create one request before executed or canceled\"\n        );\n        require(\n            ownerToLastRequestCancellation[msg.sender] <\n                block.timestamp.sub(CANCELLATION_COOLDOWN_TIMELOCK),\n            \"createRequest: Cannot create request during cancellation cooldown period\"\n        );\n\n        // Create the Request and take custody of investment asset\n        ownerToRequestInfo[msg.sender] = RequestInfo({\n            investmentAmount: _investmentAmount,\n            minSharesQuantity: _minSharesQuantity\n        });\n        ERC20(denominationAsset).safeTransferFrom(msg.sender, address(this), _investmentAmount);\n\n        emit RequestCreated(msg.sender, _investmentAmount, _minSharesQuantity);\n    }\n\n    /// @notice Executes multiple shares requests\n    /// @param _requestOwners The owners of the pending shares requests\n    function executeRequests(address[] calldata _requestOwners) external {\n        require(\n            msg.sender == fundOwner || isRequestExecutor(msg.sender),\n            \"executeRequests: Invalid caller\"\n        );\n        require(_requestOwners.length > 0, \"executeRequests: _requestOwners can not be empty\");\n\n        (\n            address[] memory buyers,\n            uint256[] memory investmentAmounts,\n            uint256[] memory minSharesQuantities,\n            uint256 totalInvestmentAmount\n        ) = __convertRequestsToBuySharesParams(_requestOwners);\n\n        // Since ComptrollerProxy instances are fully trusted,\n        // we can approve them with the max amount of the denomination asset,\n        // and only top the approval back to max if ever necessary.\n        address comptrollerProxyCopy = comptrollerProxy;\n        ERC20 denominationAssetContract = ERC20(denominationAsset);\n        if (\n            denominationAssetContract.allowance(address(this), comptrollerProxyCopy) <\n            totalInvestmentAmount\n        ) {\n            denominationAssetContract.approve(comptrollerProxyCopy, type(uint256).max);\n        }\n\n        ComptrollerLib(comptrollerProxyCopy).buyShares(\n            buyers,\n            investmentAmounts,\n            minSharesQuantities\n        );\n    }\n\n    /// @dev Helper to convert raw shares requests into the format required by buyShares().\n    /// It also removes any empty requests, which is necessary to prevent a DoS attack where a user\n    /// cancels their request earlier in the same block (can be repeated from multiple accounts).\n    /// This function also removes shares requests and fires success events as it loops through them.\n    function __convertRequestsToBuySharesParams(address[] memory _requestOwners)\n        private\n        returns (\n            address[] memory buyers_,\n            uint256[] memory investmentAmounts_,\n            uint256[] memory minSharesQuantities_,\n            uint256 totalInvestmentAmount_\n        )\n    {\n        uint256 existingRequestsCount = _requestOwners.length;\n        uint256[] memory allInvestmentAmounts = new uint256[](_requestOwners.length);\n\n        // Loop through once to get the count of existing requests\n        for (uint256 i; i < _requestOwners.length; i++) {\n            allInvestmentAmounts[i] = ownerToRequestInfo[_requestOwners[i]].investmentAmount;\n\n            if (allInvestmentAmounts[i] == 0) {\n                existingRequestsCount--;\n            }\n        }\n\n        // Loop through a second time to format requests for buyShares(),\n        // and to delete the requests and emit events early so no further looping is needed.\n        buyers_ = new address[](existingRequestsCount);\n        investmentAmounts_ = new uint256[](existingRequestsCount);\n        minSharesQuantities_ = new uint256[](existingRequestsCount);\n        uint256 existingRequestsIndex;\n        for (uint256 i; i < _requestOwners.length; i++) {\n            if (allInvestmentAmounts[i] == 0) {\n                continue;\n            }\n\n            buyers_[existingRequestsIndex] = _requestOwners[i];\n            investmentAmounts_[existingRequestsIndex] = allInvestmentAmounts[i];\n            minSharesQuantities_[existingRequestsIndex] = ownerToRequestInfo[_requestOwners[i]]\n                .minSharesQuantity;\n            totalInvestmentAmount_ = totalInvestmentAmount_.add(allInvestmentAmounts[i]);\n\n            delete ownerToRequestInfo[_requestOwners[i]];\n\n            emit RequestExecuted(\n                msg.sender,\n                buyers_[existingRequestsIndex],\n                investmentAmounts_[existingRequestsIndex],\n                minSharesQuantities_[existingRequestsIndex]\n            );\n\n            existingRequestsIndex++;\n        }\n\n        return (buyers_, investmentAmounts_, minSharesQuantities_, totalInvestmentAmount_);\n    }\n\n    ///////////////////////////////\n    // REQUEST EXECUTOR REGISTRY //\n    ///////////////////////////////\n\n    /// @notice Adds accounts to request executors\n    /// @param _requestExecutors Accounts to add\n    function addRequestExecutors(address[] calldata _requestExecutors) external onlyFundOwner {\n        require(_requestExecutors.length > 0, \"addRequestExecutors: Empty _requestExecutors\");\n\n        for (uint256 i; i < _requestExecutors.length; i++) {\n            require(\n                !isRequestExecutor(_requestExecutors[i]),\n                \"addRequestExecutors: Value already set\"\n            );\n            require(\n                _requestExecutors[i] != fundOwner,\n                \"addRequestExecutors: The fund owner cannot be added\"\n            );\n\n            acctToIsRequestExecutor[_requestExecutors[i]] = true;\n\n            emit RequestExecutorAdded(_requestExecutors[i]);\n        }\n    }\n\n    /// @notice Removes accounts from request executors\n    /// @param _requestExecutors Accounts to remove\n    function removeRequestExecutors(address[] calldata _requestExecutors) external onlyFundOwner {\n        require(_requestExecutors.length > 0, \"removeRequestExecutors: Empty _requestExecutors\");\n\n        for (uint256 i; i < _requestExecutors.length; i++) {\n            require(\n                isRequestExecutor(_requestExecutors[i]),\n                \"removeRequestExecutors: Account is not a request executor\"\n            );\n\n            acctToIsRequestExecutor[_requestExecutors[i]] = false;\n\n            emit RequestExecutorRemoved(_requestExecutors[i]);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the value of `comptrollerProxy` variable\n    /// @return comptrollerProxy_ The `comptrollerProxy` variable value\n    function getComptrollerProxy() external view returns (address comptrollerProxy_) {\n        return comptrollerProxy;\n    }\n\n    /// @notice Gets the value of `denominationAsset` variable\n    /// @return denominationAsset_ The `denominationAsset` variable value\n    function getDenominationAsset() external view returns (address denominationAsset_) {\n        return denominationAsset;\n    }\n\n    /// @notice Gets the value of `fundOwner` variable\n    /// @return fundOwner_ The `fundOwner` variable value\n    function getFundOwner() external view returns (address fundOwner_) {\n        return fundOwner;\n    }\n\n    /// @notice Gets the request info of a user\n    /// @param _requestOwner The address of the user that creates the request\n    /// @return requestInfo_ The request info created by the user\n    function getSharesRequestInfoForOwner(address _requestOwner)\n        external\n        view\n        returns (RequestInfo memory requestInfo_)\n    {\n        return ownerToRequestInfo[_requestOwner];\n    }\n\n    /// @notice Checks whether an account is a request executor\n    /// @param _who The account to check\n    /// @return isRequestExecutor_ True if _who is a request executor\n    function isRequestExecutor(address _who) public view returns (bool isRequestExecutor_) {\n        return acctToIsRequestExecutor[_who];\n    }\n}\n"
      },
      "contracts/release/peripheral/shares-requestors/IAuthUserExecutedSharesRequestor.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IAuthUserExecutedSharesRequestor Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IAuthUserExecutedSharesRequestor {\n    function init(address) external;\n}\n"
      },
      "contracts/release/peripheral/shares-requestors/AuthUserExecutedSharesRequestorFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../../core/fund/vault/VaultLib.sol\";\nimport \"./AuthUserExecutedSharesRequestorProxy.sol\";\nimport \"./IAuthUserExecutedSharesRequestor.sol\";\n\n/// @title AuthUserExecutedSharesRequestorFactory Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Deploys and maintains a record of AuthUserExecutedSharesRequestorProxy instances\ncontract AuthUserExecutedSharesRequestorFactory {\n    event SharesRequestorProxyDeployed(\n        address indexed comptrollerProxy,\n        address sharesRequestorProxy\n    );\n\n    address private immutable AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB;\n    address private immutable DISPATCHER;\n\n    mapping(address => address) private comptrollerProxyToSharesRequestorProxy;\n\n    constructor(address _dispatcher, address _authUserExecutedSharesRequestorLib) public {\n        AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB = _authUserExecutedSharesRequestorLib;\n        DISPATCHER = _dispatcher;\n    }\n\n    /// @notice Deploys a shares requestor proxy instance for a given ComptrollerProxy instance\n    /// @param _comptrollerProxy The ComptrollerProxy for which to deploy the shares requestor proxy\n    /// @return sharesRequestorProxy_ The address of the newly-deployed shares requestor proxy\n    function deploySharesRequestorProxy(address _comptrollerProxy)\n        external\n        returns (address sharesRequestorProxy_)\n    {\n        // Confirm fund is genuine\n        VaultLib vaultProxyContract = VaultLib(ComptrollerLib(_comptrollerProxy).getVaultProxy());\n        require(\n            vaultProxyContract.getAccessor() == _comptrollerProxy,\n            \"deploySharesRequestorProxy: Invalid VaultProxy for ComptrollerProxy\"\n        );\n        require(\n            IDispatcher(DISPATCHER).getFundDeployerForVaultProxy(address(vaultProxyContract)) !=\n                address(0),\n            \"deploySharesRequestorProxy: Not a genuine fund\"\n        );\n\n        // Validate that the caller is the fund owner\n        require(\n            msg.sender == vaultProxyContract.getOwner(),\n            \"deploySharesRequestorProxy: Only fund owner callable\"\n        );\n\n        // Validate that a proxy does not already exist\n        require(\n            comptrollerProxyToSharesRequestorProxy[_comptrollerProxy] == address(0),\n            \"deploySharesRequestorProxy: Proxy already exists\"\n        );\n\n        // Deploy the proxy\n        bytes memory constructData = abi.encodeWithSelector(\n            IAuthUserExecutedSharesRequestor.init.selector,\n            _comptrollerProxy\n        );\n        sharesRequestorProxy_ = address(\n            new AuthUserExecutedSharesRequestorProxy(\n                constructData,\n                AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB\n            )\n        );\n\n        comptrollerProxyToSharesRequestorProxy[_comptrollerProxy] = sharesRequestorProxy_;\n\n        emit SharesRequestorProxyDeployed(_comptrollerProxy, sharesRequestorProxy_);\n\n        return sharesRequestorProxy_;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the value of the `AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB` variable\n    /// @return authUserExecutedSharesRequestorLib_ The `AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB` variable value\n    function getAuthUserExecutedSharesRequestorLib()\n        external\n        view\n        returns (address authUserExecutedSharesRequestorLib_)\n    {\n        return AUTH_USER_EXECUTED_SHARES_REQUESTOR_LIB;\n    }\n\n    /// @notice Gets the value of the `DISPATCHER` variable\n    /// @return dispatcher_ The `DISPATCHER` variable value\n    function getDispatcher() external view returns (address dispatcher_) {\n        return DISPATCHER;\n    }\n\n    /// @notice Gets the AuthUserExecutedSharesRequestorProxy associated with the given ComptrollerProxy\n    /// @param _comptrollerProxy The ComptrollerProxy for which to get the associated AuthUserExecutedSharesRequestorProxy\n    /// @return sharesRequestorProxy_ The associated AuthUserExecutedSharesRequestorProxy address\n    function getSharesRequestorProxyForComptrollerProxy(address _comptrollerProxy)\n        external\n        view\n        returns (address sharesRequestorProxy_)\n    {\n        return comptrollerProxyToSharesRequestorProxy[_comptrollerProxy];\n    }\n}\n"
      },
      "contracts/release/peripheral/shares-requestors/AuthUserExecutedSharesRequestorProxy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/Proxy.sol\";\n\ncontract AuthUserExecutedSharesRequestorProxy is Proxy {\n    constructor(bytes memory _constructData, address _authUserExecutedSharesRequestorLib)\n        public\n        Proxy(_constructData, _authUserExecutedSharesRequestorLib)\n    {}\n}\n"
      },
      "contracts/release/utils/Proxy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title Proxy Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A proxy contract for all Proxy instances\n/// @dev The recommended implementation of a Proxy in EIP-1822, updated for solc 0.6.12,\n/// and using the EIP-1967 storage slot for the proxiable implementation.\n/// i.e., `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`, which is\n/// \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\"\n/// See: https://eips.ethereum.org/EIPS/eip-1822\ncontract Proxy {\n    constructor(bytes memory _constructData, address _contractLogic) public {\n        assembly {\n            sstore(\n                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,\n                _contractLogic\n            )\n        }\n        (bool success, bytes memory returnData) = _contractLogic.delegatecall(_constructData);\n        require(success, string(returnData));\n    }\n\n    fallback() external payable {\n        assembly {\n            let contractLogic := sload(\n                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\n            )\n            calldatacopy(0x0, 0x0, calldatasize())\n            let success := delegatecall(\n                sub(gas(), 10000),\n                contractLogic,\n                0x0,\n                calldatasize(),\n                0,\n                0\n            )\n            let retSz := returndatasize()\n            returndatacopy(0, 0, retSz)\n            switch success\n                case 0 {\n                    revert(0, retSz)\n                }\n                default {\n                    return(0, retSz)\n                }\n        }\n    }\n}\n"
      },
      "contracts/release/core/fund/comptroller/ComptrollerProxy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../utils/Proxy.sol\";\n\n/// @title ComptrollerProxy Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A proxy contract for all ComptrollerProxy instances\ncontract ComptrollerProxy is Proxy {\n    constructor(bytes memory _constructData, address _comptrollerLib)\n        public\n        Proxy(_constructData, _comptrollerLib)\n    {}\n}\n"
      },
      "contracts/release/core/fund-deployer/FundDeployer.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../../../persistent/dispatcher/IDispatcher.sol\";\nimport \"../../../persistent/utils/IMigrationHookHandler.sol\";\nimport \"../fund/comptroller/IComptroller.sol\";\nimport \"../fund/comptroller/ComptrollerProxy.sol\";\nimport \"../fund/vault/IVault.sol\";\nimport \"./IFundDeployer.sol\";\n\n/// @title FundDeployer Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice The top-level contract of the release.\n/// It primarily coordinates fund deployment and fund migration, but\n/// it is also deferred to for contract access control and for allowed calls\n/// that can be made with a fund's VaultProxy as the msg.sender.\ncontract FundDeployer is IFundDeployer, IMigrationHookHandler {\n    event ComptrollerLibSet(address comptrollerLib);\n\n    event ComptrollerProxyDeployed(\n        address indexed creator,\n        address comptrollerProxy,\n        address indexed denominationAsset,\n        uint256 sharesActionTimelock,\n        bytes feeManagerConfigData,\n        bytes policyManagerConfigData,\n        bool indexed forMigration\n    );\n\n    event NewFundCreated(\n        address indexed creator,\n        address comptrollerProxy,\n        address vaultProxy,\n        address indexed fundOwner,\n        string fundName,\n        address indexed denominationAsset,\n        uint256 sharesActionTimelock,\n        bytes feeManagerConfigData,\n        bytes policyManagerConfigData\n    );\n\n    event ReleaseStatusSet(ReleaseStatus indexed prevStatus, ReleaseStatus indexed nextStatus);\n\n    event VaultCallDeregistered(address indexed contractAddress, bytes4 selector);\n\n    event VaultCallRegistered(address indexed contractAddress, bytes4 selector);\n\n    // Constants\n    address private immutable CREATOR;\n    address private immutable DISPATCHER;\n    address private immutable VAULT_LIB;\n\n    // Pseudo-constants (can only be set once)\n    address private comptrollerLib;\n\n    // Storage\n    ReleaseStatus private releaseStatus;\n    mapping(address => mapping(bytes4 => bool)) private contractToSelectorToIsRegisteredVaultCall;\n    mapping(address => address) private pendingComptrollerProxyToCreator;\n\n    modifier onlyLiveRelease() {\n        require(releaseStatus == ReleaseStatus.Live, \"Release is not Live\");\n        _;\n    }\n\n    modifier onlyMigrator(address _vaultProxy) {\n        require(\n            IVault(_vaultProxy).canMigrate(msg.sender),\n            \"Only a permissioned migrator can call this function\"\n        );\n        _;\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == getOwner(), \"Only the contract owner can call this function\");\n        _;\n    }\n\n    modifier onlyPendingComptrollerProxyCreator(address _comptrollerProxy) {\n        require(\n            msg.sender == pendingComptrollerProxyToCreator[_comptrollerProxy],\n            \"Only the ComptrollerProxy creator can call this function\"\n        );\n        _;\n    }\n\n    constructor(\n        address _dispatcher,\n        address _vaultLib,\n        address[] memory _vaultCallContracts,\n        bytes4[] memory _vaultCallSelectors\n    ) public {\n        if (_vaultCallContracts.length > 0) {\n            __registerVaultCalls(_vaultCallContracts, _vaultCallSelectors);\n        }\n        CREATOR = msg.sender;\n        DISPATCHER = _dispatcher;\n        VAULT_LIB = _vaultLib;\n    }\n\n    /////////////\n    // GENERAL //\n    /////////////\n\n    /// @notice Sets the comptrollerLib\n    /// @param _comptrollerLib The ComptrollerLib contract address\n    /// @dev Can only be set once\n    function setComptrollerLib(address _comptrollerLib) external onlyOwner {\n        require(\n            comptrollerLib == address(0),\n            \"setComptrollerLib: This value can only be set once\"\n        );\n\n        comptrollerLib = _comptrollerLib;\n\n        emit ComptrollerLibSet(_comptrollerLib);\n    }\n\n    /// @notice Sets the status of the protocol to a new state\n    /// @param _nextStatus The next status state to set\n    function setReleaseStatus(ReleaseStatus _nextStatus) external {\n        require(\n            msg.sender == IDispatcher(DISPATCHER).getOwner(),\n            \"setReleaseStatus: Only the Dispatcher owner can call this function\"\n        );\n        require(\n            _nextStatus != ReleaseStatus.PreLaunch,\n            \"setReleaseStatus: Cannot return to PreLaunch status\"\n        );\n        require(\n            comptrollerLib != address(0),\n            \"setReleaseStatus: Can only set the release status when comptrollerLib is set\"\n        );\n\n        ReleaseStatus prevStatus = releaseStatus;\n        require(_nextStatus != prevStatus, \"setReleaseStatus: _nextStatus is the current status\");\n\n        releaseStatus = _nextStatus;\n\n        emit ReleaseStatusSet(prevStatus, _nextStatus);\n    }\n\n    /// @notice Gets the current owner of the contract\n    /// @return owner_ The contract owner address\n    /// @dev Dynamically gets the owner based on the Protocol status. The owner is initially the\n    /// contract's deployer, for convenience in setting up configuration.\n    /// Ownership is claimed when the owner of the Dispatcher contract (the Enzyme Council)\n    /// sets the releaseStatus to `Live`.\n    function getOwner() public view override returns (address owner_) {\n        if (releaseStatus == ReleaseStatus.PreLaunch) {\n            return CREATOR;\n        }\n\n        return IDispatcher(DISPATCHER).getOwner();\n    }\n\n    ///////////////////\n    // FUND CREATION //\n    ///////////////////\n\n    /// @notice Creates a fully-configured ComptrollerProxy, to which a fund from a previous\n    /// release can migrate in a subsequent step\n    /// @param _denominationAsset The contract address of the denomination asset for the fund\n    /// @param _sharesActionTimelock The minimum number of seconds between any two \"shares actions\"\n    /// (buying or selling shares) by the same user\n    /// @param _feeManagerConfigData Bytes data for the fees to be enabled for the fund\n    /// @param _policyManagerConfigData Bytes data for the policies to be enabled for the fund\n    /// @return comptrollerProxy_ The address of the ComptrollerProxy deployed during this action\n    function createMigratedFundConfig(\n        address _denominationAsset,\n        uint256 _sharesActionTimelock,\n        bytes calldata _feeManagerConfigData,\n        bytes calldata _policyManagerConfigData\n    ) external onlyLiveRelease returns (address comptrollerProxy_) {\n        comptrollerProxy_ = __deployComptrollerProxy(\n            _denominationAsset,\n            _sharesActionTimelock,\n            _feeManagerConfigData,\n            _policyManagerConfigData,\n            true\n        );\n\n        pendingComptrollerProxyToCreator[comptrollerProxy_] = msg.sender;\n\n        return comptrollerProxy_;\n    }\n\n    /// @notice Creates a new fund\n    /// @param _fundOwner The address of the owner for the fund\n    /// @param _fundName The name of the fund\n    /// @param _denominationAsset The contract address of the denomination asset for the fund\n    /// @param _sharesActionTimelock The minimum number of seconds between any two \"shares actions\"\n    /// (buying or selling shares) by the same user\n    /// @param _feeManagerConfigData Bytes data for the fees to be enabled for the fund\n    /// @param _policyManagerConfigData Bytes data for the policies to be enabled for the fund\n    /// @return comptrollerProxy_ The address of the ComptrollerProxy deployed during this action\n    function createNewFund(\n        address _fundOwner,\n        string calldata _fundName,\n        address _denominationAsset,\n        uint256 _sharesActionTimelock,\n        bytes calldata _feeManagerConfigData,\n        bytes calldata _policyManagerConfigData\n    ) external onlyLiveRelease returns (address comptrollerProxy_, address vaultProxy_) {\n        return\n            __createNewFund(\n                _fundOwner,\n                _fundName,\n                _denominationAsset,\n                _sharesActionTimelock,\n                _feeManagerConfigData,\n                _policyManagerConfigData\n            );\n    }\n\n    /// @dev Helper to avoid the stack-too-deep error during createNewFund\n    function __createNewFund(\n        address _fundOwner,\n        string memory _fundName,\n        address _denominationAsset,\n        uint256 _sharesActionTimelock,\n        bytes memory _feeManagerConfigData,\n        bytes memory _policyManagerConfigData\n    ) private returns (address comptrollerProxy_, address vaultProxy_) {\n        require(_fundOwner != address(0), \"__createNewFund: _owner cannot be empty\");\n\n        comptrollerProxy_ = __deployComptrollerProxy(\n            _denominationAsset,\n            _sharesActionTimelock,\n            _feeManagerConfigData,\n            _policyManagerConfigData,\n            false\n        );\n\n        vaultProxy_ = IDispatcher(DISPATCHER).deployVaultProxy(\n            VAULT_LIB,\n            _fundOwner,\n            comptrollerProxy_,\n            _fundName\n        );\n\n        IComptroller(comptrollerProxy_).activate(vaultProxy_, false);\n\n        emit NewFundCreated(\n            msg.sender,\n            comptrollerProxy_,\n            vaultProxy_,\n            _fundOwner,\n            _fundName,\n            _denominationAsset,\n            _sharesActionTimelock,\n            _feeManagerConfigData,\n            _policyManagerConfigData\n        );\n\n        return (comptrollerProxy_, vaultProxy_);\n    }\n\n    /// @dev Helper function to deploy a configured ComptrollerProxy\n    function __deployComptrollerProxy(\n        address _denominationAsset,\n        uint256 _sharesActionTimelock,\n        bytes memory _feeManagerConfigData,\n        bytes memory _policyManagerConfigData,\n        bool _forMigration\n    ) private returns (address comptrollerProxy_) {\n        require(\n            _denominationAsset != address(0),\n            \"__deployComptrollerProxy: _denominationAsset cannot be empty\"\n        );\n\n        bytes memory constructData = abi.encodeWithSelector(\n            IComptroller.init.selector,\n            _denominationAsset,\n            _sharesActionTimelock\n        );\n        comptrollerProxy_ = address(new ComptrollerProxy(constructData, comptrollerLib));\n\n        if (_feeManagerConfigData.length > 0 || _policyManagerConfigData.length > 0) {\n            IComptroller(comptrollerProxy_).configureExtensions(\n                _feeManagerConfigData,\n                _policyManagerConfigData\n            );\n        }\n\n        emit ComptrollerProxyDeployed(\n            msg.sender,\n            comptrollerProxy_,\n            _denominationAsset,\n            _sharesActionTimelock,\n            _feeManagerConfigData,\n            _policyManagerConfigData,\n            _forMigration\n        );\n\n        return comptrollerProxy_;\n    }\n\n    //////////////////\n    // MIGRATION IN //\n    //////////////////\n\n    /// @notice Cancels fund migration\n    /// @param _vaultProxy The VaultProxy for which to cancel migration\n    function cancelMigration(address _vaultProxy) external {\n        __cancelMigration(_vaultProxy, false);\n    }\n\n    /// @notice Cancels fund migration, bypassing any failures.\n    /// Should be used in an emergency only.\n    /// @param _vaultProxy The VaultProxy for which to cancel migration\n    function cancelMigrationEmergency(address _vaultProxy) external {\n        __cancelMigration(_vaultProxy, true);\n    }\n\n    /// @notice Executes fund migration\n    /// @param _vaultProxy The VaultProxy for which to execute the migration\n    function executeMigration(address _vaultProxy) external {\n        __executeMigration(_vaultProxy, false);\n    }\n\n    /// @notice Executes fund migration, bypassing any failures.\n    /// Should be used in an emergency only.\n    /// @param _vaultProxy The VaultProxy for which to execute the migration\n    function executeMigrationEmergency(address _vaultProxy) external {\n        __executeMigration(_vaultProxy, true);\n    }\n\n    /// @dev Unimplemented\n    function invokeMigrationInCancelHook(\n        address,\n        address,\n        address,\n        address\n    ) external virtual override {\n        return;\n    }\n\n    /// @notice Signal a fund migration\n    /// @param _vaultProxy The VaultProxy for which to signal the migration\n    /// @param _comptrollerProxy The ComptrollerProxy for which to signal the migration\n    function signalMigration(address _vaultProxy, address _comptrollerProxy) external {\n        __signalMigration(_vaultProxy, _comptrollerProxy, false);\n    }\n\n    /// @notice Signal a fund migration, bypassing any failures.\n    /// Should be used in an emergency only.\n    /// @param _vaultProxy The VaultProxy for which to signal the migration\n    /// @param _comptrollerProxy The ComptrollerProxy for which to signal the migration\n    function signalMigrationEmergency(address _vaultProxy, address _comptrollerProxy) external {\n        __signalMigration(_vaultProxy, _comptrollerProxy, true);\n    }\n\n    /// @dev Helper to cancel a migration\n    function __cancelMigration(address _vaultProxy, bool _bypassFailure)\n        private\n        onlyLiveRelease\n        onlyMigrator(_vaultProxy)\n    {\n        IDispatcher(DISPATCHER).cancelMigration(_vaultProxy, _bypassFailure);\n    }\n\n    /// @dev Helper to execute a migration\n    function __executeMigration(address _vaultProxy, bool _bypassFailure)\n        private\n        onlyLiveRelease\n        onlyMigrator(_vaultProxy)\n    {\n        IDispatcher dispatcherContract = IDispatcher(DISPATCHER);\n\n        (, address comptrollerProxy, , ) = dispatcherContract\n            .getMigrationRequestDetailsForVaultProxy(_vaultProxy);\n\n        dispatcherContract.executeMigration(_vaultProxy, _bypassFailure);\n\n        IComptroller(comptrollerProxy).activate(_vaultProxy, true);\n\n        delete pendingComptrollerProxyToCreator[comptrollerProxy];\n    }\n\n    /// @dev Helper to signal a migration\n    function __signalMigration(\n        address _vaultProxy,\n        address _comptrollerProxy,\n        bool _bypassFailure\n    )\n        private\n        onlyLiveRelease\n        onlyPendingComptrollerProxyCreator(_comptrollerProxy)\n        onlyMigrator(_vaultProxy)\n    {\n        IDispatcher(DISPATCHER).signalMigration(\n            _vaultProxy,\n            _comptrollerProxy,\n            VAULT_LIB,\n            _bypassFailure\n        );\n    }\n\n    ///////////////////\n    // MIGRATION OUT //\n    ///////////////////\n\n    /// @notice Allows \"hooking into\" specific moments in the migration pipeline\n    /// to execute arbitrary logic during a migration out of this release\n    /// @param _vaultProxy The VaultProxy being migrated\n    function invokeMigrationOutHook(\n        MigrationOutHook _hook,\n        address _vaultProxy,\n        address,\n        address,\n        address\n    ) external override {\n        if (_hook != MigrationOutHook.PreMigrate) {\n            return;\n        }\n\n        require(\n            msg.sender == DISPATCHER,\n            \"postMigrateOriginHook: Only Dispatcher can call this function\"\n        );\n\n        // Must use PreMigrate hook to get the ComptrollerProxy from the VaultProxy\n        address comptrollerProxy = IVault(_vaultProxy).getAccessor();\n\n        // Wind down fund and destroy its config\n        IComptroller(comptrollerProxy).destruct();\n    }\n\n    //////////////\n    // REGISTRY //\n    //////////////\n\n    /// @notice De-registers allowed arbitrary contract calls that can be sent from the VaultProxy\n    /// @param _contracts The contracts of the calls to de-register\n    /// @param _selectors The selectors of the calls to de-register\n    function deregisterVaultCalls(address[] calldata _contracts, bytes4[] calldata _selectors)\n        external\n        onlyOwner\n    {\n        require(_contracts.length > 0, \"deregisterVaultCalls: Empty _contracts\");\n        require(\n            _contracts.length == _selectors.length,\n            \"deregisterVaultCalls: Uneven input arrays\"\n        );\n\n        for (uint256 i; i < _contracts.length; i++) {\n            require(\n                isRegisteredVaultCall(_contracts[i], _selectors[i]),\n                \"deregisterVaultCalls: Call not registered\"\n            );\n\n            contractToSelectorToIsRegisteredVaultCall[_contracts[i]][_selectors[i]] = false;\n\n            emit VaultCallDeregistered(_contracts[i], _selectors[i]);\n        }\n    }\n\n    /// @notice Registers allowed arbitrary contract calls that can be sent from the VaultProxy\n    /// @param _contracts The contracts of the calls to register\n    /// @param _selectors The selectors of the calls to register\n    function registerVaultCalls(address[] calldata _contracts, bytes4[] calldata _selectors)\n        external\n        onlyOwner\n    {\n        require(_contracts.length > 0, \"registerVaultCalls: Empty _contracts\");\n\n        __registerVaultCalls(_contracts, _selectors);\n    }\n\n    /// @dev Helper to register allowed vault calls\n    function __registerVaultCalls(address[] memory _contracts, bytes4[] memory _selectors)\n        private\n    {\n        require(\n            _contracts.length == _selectors.length,\n            \"__registerVaultCalls: Uneven input arrays\"\n        );\n\n        for (uint256 i; i < _contracts.length; i++) {\n            require(\n                !isRegisteredVaultCall(_contracts[i], _selectors[i]),\n                \"__registerVaultCalls: Call already registered\"\n            );\n\n            contractToSelectorToIsRegisteredVaultCall[_contracts[i]][_selectors[i]] = true;\n\n            emit VaultCallRegistered(_contracts[i], _selectors[i]);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `comptrollerLib` variable value\n    /// @return comptrollerLib_ The `comptrollerLib` variable value\n    function getComptrollerLib() external view returns (address comptrollerLib_) {\n        return comptrollerLib;\n    }\n\n    /// @notice Gets the `CREATOR` variable value\n    /// @return creator_ The `CREATOR` variable value\n    function getCreator() external view returns (address creator_) {\n        return CREATOR;\n    }\n\n    /// @notice Gets the `DISPATCHER` variable value\n    /// @return dispatcher_ The `DISPATCHER` variable value\n    function getDispatcher() external view returns (address dispatcher_) {\n        return DISPATCHER;\n    }\n\n    /// @notice Gets the creator of a pending ComptrollerProxy\n    /// @return pendingComptrollerProxyCreator_ The pending ComptrollerProxy creator\n    function getPendingComptrollerProxyCreator(address _comptrollerProxy)\n        external\n        view\n        returns (address pendingComptrollerProxyCreator_)\n    {\n        return pendingComptrollerProxyToCreator[_comptrollerProxy];\n    }\n\n    /// @notice Gets the `releaseStatus` variable value\n    /// @return status_ The `releaseStatus` variable value\n    function getReleaseStatus() external view override returns (ReleaseStatus status_) {\n        return releaseStatus;\n    }\n\n    /// @notice Gets the `VAULT_LIB` variable value\n    /// @return vaultLib_ The `VAULT_LIB` variable value\n    function getVaultLib() external view returns (address vaultLib_) {\n        return VAULT_LIB;\n    }\n\n    /// @notice Checks if a contract call is registered\n    /// @param _contract The contract of the call to check\n    /// @param _selector The selector of the call to check\n    /// @return isRegistered_ True if the call is registered\n    function isRegisteredVaultCall(address _contract, bytes4 _selector)\n        public\n        view\n        override\n        returns (bool isRegistered_)\n    {\n        return contractToSelectorToIsRegisteredVaultCall[_contract][_selector];\n    }\n}\n"
      },
      "contracts/persistent/utils/IMigrationHookHandler.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title IMigrationHookHandler Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IMigrationHookHandler {\n    enum MigrationOutHook {PreSignal, PostSignal, PreMigrate, PostMigrate, PostCancel}\n\n    function invokeMigrationInCancelHook(\n        address _vaultProxy,\n        address _prevFundDeployer,\n        address _nextVaultAccessor,\n        address _nextVaultLib\n    ) external;\n\n    function invokeMigrationOutHook(\n        MigrationOutHook _hook,\n        address _vaultProxy,\n        address _nextFundDeployer,\n        address _nextVaultAccessor,\n        address _nextVaultLib\n    ) external;\n}\n"
      },
      "contracts/release/extensions/integration-manager/IntegrationManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/EnumerableSet.sol\";\nimport \"../../core/fund/vault/IVault.sol\";\nimport \"../../infrastructure/price-feeds/derivatives/IDerivativePriceFeed.sol\";\nimport \"../../infrastructure/price-feeds/primitives/IPrimitivePriceFeed.sol\";\nimport \"../../utils/AddressArrayLib.sol\";\nimport \"../../utils/AssetFinalityResolver.sol\";\nimport \"../policy-manager/IPolicyManager.sol\";\nimport \"../utils/ExtensionBase.sol\";\nimport \"../utils/FundDeployerOwnerMixin.sol\";\nimport \"../utils/PermissionedVaultActionMixin.sol\";\nimport \"./integrations/IIntegrationAdapter.sol\";\nimport \"./IIntegrationManager.sol\";\n\n/// @title IntegrationManager\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Extension to handle DeFi integration actions for funds\ncontract IntegrationManager is\n    IIntegrationManager,\n    ExtensionBase,\n    FundDeployerOwnerMixin,\n    PermissionedVaultActionMixin,\n    AssetFinalityResolver\n{\n    using AddressArrayLib for address[];\n    using EnumerableSet for EnumerableSet.AddressSet;\n    using SafeMath for uint256;\n\n    event AdapterDeregistered(address indexed adapter, string indexed identifier);\n\n    event AdapterRegistered(address indexed adapter, string indexed identifier);\n\n    event AuthUserAddedForFund(address indexed comptrollerProxy, address indexed account);\n\n    event AuthUserRemovedForFund(address indexed comptrollerProxy, address indexed account);\n\n    event CallOnIntegrationExecutedForFund(\n        address indexed comptrollerProxy,\n        address vaultProxy,\n        address caller,\n        address indexed adapter,\n        bytes4 indexed selector,\n        bytes integrationData,\n        address[] incomingAssets,\n        uint256[] incomingAssetAmounts,\n        address[] outgoingAssets,\n        uint256[] outgoingAssetAmounts\n    );\n\n    address private immutable DERIVATIVE_PRICE_FEED;\n    address private immutable POLICY_MANAGER;\n    address private immutable PRIMITIVE_PRICE_FEED;\n\n    EnumerableSet.AddressSet private registeredAdapters;\n\n    mapping(address => mapping(address => bool)) private comptrollerProxyToAcctToIsAuthUser;\n\n    constructor(\n        address _fundDeployer,\n        address _policyManager,\n        address _derivativePriceFeed,\n        address _primitivePriceFeed,\n        address _synthetixPriceFeed,\n        address _synthetixAddressResolver\n    )\n        public\n        FundDeployerOwnerMixin(_fundDeployer)\n        AssetFinalityResolver(_synthetixPriceFeed, _synthetixAddressResolver)\n    {\n        DERIVATIVE_PRICE_FEED = _derivativePriceFeed;\n        POLICY_MANAGER = _policyManager;\n        PRIMITIVE_PRICE_FEED = _primitivePriceFeed;\n    }\n\n    /////////////\n    // GENERAL //\n    /////////////\n\n    /// @notice Activates the extension by storing the VaultProxy\n    function activateForFund(bool) external override {\n        __setValidatedVaultProxy(msg.sender);\n    }\n\n    /// @notice Authorizes a user to act on behalf of a fund via the IntegrationManager\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _who The user to authorize\n    function addAuthUserForFund(address _comptrollerProxy, address _who) external {\n        __validateSetAuthUser(_comptrollerProxy, _who, true);\n\n        comptrollerProxyToAcctToIsAuthUser[_comptrollerProxy][_who] = true;\n\n        emit AuthUserAddedForFund(_comptrollerProxy, _who);\n    }\n\n    /// @notice Deactivate the extension by destroying storage\n    function deactivateForFund() external override {\n        delete comptrollerProxyToVaultProxy[msg.sender];\n    }\n\n    /// @notice Removes an authorized user from the IntegrationManager for the given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _who The authorized user to remove\n    function removeAuthUserForFund(address _comptrollerProxy, address _who) external {\n        __validateSetAuthUser(_comptrollerProxy, _who, false);\n\n        comptrollerProxyToAcctToIsAuthUser[_comptrollerProxy][_who] = false;\n\n        emit AuthUserRemovedForFund(_comptrollerProxy, _who);\n    }\n\n    /// @notice Checks whether an account is an authorized IntegrationManager user for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _who The account to check\n    /// @return isAuthUser_ True if the account is an authorized user or the fund owner\n    function isAuthUserForFund(address _comptrollerProxy, address _who)\n        public\n        view\n        returns (bool isAuthUser_)\n    {\n        return\n            comptrollerProxyToAcctToIsAuthUser[_comptrollerProxy][_who] ||\n            _who == IVault(comptrollerProxyToVaultProxy[_comptrollerProxy]).getOwner();\n    }\n\n    /// @dev Helper to validate calls to update comptrollerProxyToAcctToIsAuthUser\n    function __validateSetAuthUser(\n        address _comptrollerProxy,\n        address _who,\n        bool _nextIsAuthUser\n    ) private view {\n        require(\n            comptrollerProxyToVaultProxy[_comptrollerProxy] != address(0),\n            \"__validateSetAuthUser: Fund has not been activated\"\n        );\n\n        address fundOwner = IVault(comptrollerProxyToVaultProxy[_comptrollerProxy]).getOwner();\n        require(\n            msg.sender == fundOwner,\n            \"__validateSetAuthUser: Only the fund owner can call this function\"\n        );\n        require(_who != fundOwner, \"__validateSetAuthUser: Cannot set for the fund owner\");\n\n        if (_nextIsAuthUser) {\n            require(\n                !comptrollerProxyToAcctToIsAuthUser[_comptrollerProxy][_who],\n                \"__validateSetAuthUser: Account is already an authorized user\"\n            );\n        } else {\n            require(\n                comptrollerProxyToAcctToIsAuthUser[_comptrollerProxy][_who],\n                \"__validateSetAuthUser: Account is not an authorized user\"\n            );\n        }\n    }\n\n    ///////////////////////////////\n    // CALL-ON-EXTENSION ACTIONS //\n    ///////////////////////////////\n\n    /// @notice Receives a dispatched `callOnExtension` from a fund's ComptrollerProxy\n    /// @param _caller The user who called for this action\n    /// @param _actionId An ID representing the desired action\n    /// @param _callArgs The encoded args for the action\n    function receiveCallFromComptroller(\n        address _caller,\n        uint256 _actionId,\n        bytes calldata _callArgs\n    ) external override {\n        // Since we validate and store the ComptrollerProxy-VaultProxy pairing during\n        // activateForFund(), this function does not require further validation of the\n        // sending ComptrollerProxy\n        address vaultProxy = comptrollerProxyToVaultProxy[msg.sender];\n        require(vaultProxy != address(0), \"receiveCallFromComptroller: Fund is not active\");\n        require(\n            isAuthUserForFund(msg.sender, _caller),\n            \"receiveCallFromComptroller: Not an authorized user\"\n        );\n\n        // Dispatch the action\n        if (_actionId == 0) {\n            __callOnIntegration(_caller, vaultProxy, _callArgs);\n        } else if (_actionId == 1) {\n            __addZeroBalanceTrackedAssets(vaultProxy, _callArgs);\n        } else if (_actionId == 2) {\n            __removeZeroBalanceTrackedAssets(vaultProxy, _callArgs);\n        } else {\n            revert(\"receiveCallFromComptroller: Invalid _actionId\");\n        }\n    }\n\n    /// @dev Adds assets with a zero balance as tracked assets of the fund\n    function __addZeroBalanceTrackedAssets(address _vaultProxy, bytes memory _callArgs) private {\n        address[] memory assets = abi.decode(_callArgs, (address[]));\n        for (uint256 i; i < assets.length; i++) {\n            require(\n                __finalizeIfSynthAndGetAssetBalance(_vaultProxy, assets[i], true) == 0,\n                \"__addZeroBalanceTrackedAssets: Balance is not zero\"\n            );\n\n            __addTrackedAsset(msg.sender, assets[i]);\n        }\n    }\n\n    /// @dev Removes assets with a zero balance from tracked assets of the fund\n    function __removeZeroBalanceTrackedAssets(address _vaultProxy, bytes memory _callArgs)\n        private\n    {\n        address[] memory assets = abi.decode(_callArgs, (address[]));\n        address denominationAsset = IComptroller(msg.sender).getDenominationAsset();\n        for (uint256 i; i < assets.length; i++) {\n            require(\n                assets[i] != denominationAsset,\n                \"__removeZeroBalanceTrackedAssets: Cannot remove denomination asset\"\n            );\n            require(\n                __finalizeIfSynthAndGetAssetBalance(_vaultProxy, assets[i], true) == 0,\n                \"__removeZeroBalanceTrackedAssets: Balance is not zero\"\n            );\n\n            __removeTrackedAsset(msg.sender, assets[i]);\n        }\n    }\n\n    /////////////////////////\n    // CALL ON INTEGRATION //\n    /////////////////////////\n\n    /// @notice Universal method for calling third party contract functions through adapters\n    /// @param _caller The caller of this function via the ComptrollerProxy\n    /// @param _vaultProxy The VaultProxy of the fund\n    /// @param _callArgs The encoded args for this function\n    /// - _adapter Adapter of the integration on which to execute a call\n    /// - _selector Method selector of the adapter method to execute\n    /// - _integrationData Encoded arguments specific to the adapter\n    /// @dev msg.sender is the ComptrollerProxy.\n    /// Refer to specific adapter to see how to encode its arguments.\n    function __callOnIntegration(\n        address _caller,\n        address _vaultProxy,\n        bytes memory _callArgs\n    ) private {\n        (\n            address adapter,\n            bytes4 selector,\n            bytes memory integrationData\n        ) = __decodeCallOnIntegrationArgs(_callArgs);\n\n        __preCoIHook(adapter, selector);\n\n        /// Passing decoded _callArgs leads to stack-too-deep error\n        (\n            address[] memory incomingAssets,\n            uint256[] memory incomingAssetAmounts,\n            address[] memory outgoingAssets,\n            uint256[] memory outgoingAssetAmounts\n        ) = __callOnIntegrationInner(_vaultProxy, _callArgs);\n\n        __postCoIHook(\n            adapter,\n            selector,\n            incomingAssets,\n            incomingAssetAmounts,\n            outgoingAssets,\n            outgoingAssetAmounts\n        );\n\n        __emitCoIEvent(\n            _vaultProxy,\n            _caller,\n            adapter,\n            selector,\n            integrationData,\n            incomingAssets,\n            incomingAssetAmounts,\n            outgoingAssets,\n            outgoingAssetAmounts\n        );\n    }\n\n    /// @dev Helper to execute the bulk of logic of callOnIntegration.\n    /// Avoids the stack-too-deep-error.\n    function __callOnIntegrationInner(address vaultProxy, bytes memory _callArgs)\n        private\n        returns (\n            address[] memory incomingAssets_,\n            uint256[] memory incomingAssetAmounts_,\n            address[] memory outgoingAssets_,\n            uint256[] memory outgoingAssetAmounts_\n        )\n    {\n        (\n            address[] memory expectedIncomingAssets,\n            uint256[] memory preCallIncomingAssetBalances,\n            uint256[] memory minIncomingAssetAmounts,\n            SpendAssetsHandleType spendAssetsHandleType,\n            address[] memory spendAssets,\n            uint256[] memory maxSpendAssetAmounts,\n            uint256[] memory preCallSpendAssetBalances\n        ) = __preProcessCoI(vaultProxy, _callArgs);\n\n        __executeCoI(\n            vaultProxy,\n            _callArgs,\n            abi.encode(\n                spendAssetsHandleType,\n                spendAssets,\n                maxSpendAssetAmounts,\n                expectedIncomingAssets\n            )\n        );\n\n        (\n            incomingAssets_,\n            incomingAssetAmounts_,\n            outgoingAssets_,\n            outgoingAssetAmounts_\n        ) = __postProcessCoI(\n            vaultProxy,\n            expectedIncomingAssets,\n            preCallIncomingAssetBalances,\n            minIncomingAssetAmounts,\n            spendAssetsHandleType,\n            spendAssets,\n            maxSpendAssetAmounts,\n            preCallSpendAssetBalances\n        );\n\n        return (incomingAssets_, incomingAssetAmounts_, outgoingAssets_, outgoingAssetAmounts_);\n    }\n\n    /// @dev Helper to decode CoI args\n    function __decodeCallOnIntegrationArgs(bytes memory _callArgs)\n        private\n        pure\n        returns (\n            address adapter_,\n            bytes4 selector_,\n            bytes memory integrationData_\n        )\n    {\n        return abi.decode(_callArgs, (address, bytes4, bytes));\n    }\n\n    /// @dev Helper to emit the CallOnIntegrationExecuted event.\n    /// Avoids stack-too-deep error.\n    function __emitCoIEvent(\n        address _vaultProxy,\n        address _caller,\n        address _adapter,\n        bytes4 _selector,\n        bytes memory _integrationData,\n        address[] memory _incomingAssets,\n        uint256[] memory _incomingAssetAmounts,\n        address[] memory _outgoingAssets,\n        uint256[] memory _outgoingAssetAmounts\n    ) private {\n        emit CallOnIntegrationExecutedForFund(\n            msg.sender,\n            _vaultProxy,\n            _caller,\n            _adapter,\n            _selector,\n            _integrationData,\n            _incomingAssets,\n            _incomingAssetAmounts,\n            _outgoingAssets,\n            _outgoingAssetAmounts\n        );\n    }\n\n    /// @dev Helper to execute a call to an integration\n    /// @dev Avoids stack-too-deep error\n    function __executeCoI(\n        address _vaultProxy,\n        bytes memory _callArgs,\n        bytes memory _encodedAssetTransferArgs\n    ) private {\n        (\n            address adapter,\n            bytes4 selector,\n            bytes memory integrationData\n        ) = __decodeCallOnIntegrationArgs(_callArgs);\n\n        (bool success, bytes memory returnData) = adapter.call(\n            abi.encodeWithSelector(\n                selector,\n                _vaultProxy,\n                integrationData,\n                _encodedAssetTransferArgs\n            )\n        );\n        require(success, string(returnData));\n    }\n\n    /// @dev Helper to get the vault's balance of a particular asset\n    function __getVaultAssetBalance(address _vaultProxy, address _asset)\n        private\n        view\n        returns (uint256)\n    {\n        return ERC20(_asset).balanceOf(_vaultProxy);\n    }\n\n    /// @dev Helper to check if an asset is supported\n    function __isSupportedAsset(address _asset) private view returns (bool isSupported_) {\n        return\n            IPrimitivePriceFeed(PRIMITIVE_PRICE_FEED).isSupportedAsset(_asset) ||\n            IDerivativePriceFeed(DERIVATIVE_PRICE_FEED).isSupportedAsset(_asset);\n    }\n\n    /// @dev Helper for the actions to take on external contracts prior to executing CoI\n    function __preCoIHook(address _adapter, bytes4 _selector) private {\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            msg.sender,\n            IPolicyManager.PolicyHook.PreCallOnIntegration,\n            abi.encode(_adapter, _selector)\n        );\n    }\n\n    /// @dev Helper for the internal actions to take prior to executing CoI\n    function __preProcessCoI(address _vaultProxy, bytes memory _callArgs)\n        private\n        returns (\n            address[] memory expectedIncomingAssets_,\n            uint256[] memory preCallIncomingAssetBalances_,\n            uint256[] memory minIncomingAssetAmounts_,\n            SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory maxSpendAssetAmounts_,\n            uint256[] memory preCallSpendAssetBalances_\n        )\n    {\n        (\n            address adapter,\n            bytes4 selector,\n            bytes memory integrationData\n        ) = __decodeCallOnIntegrationArgs(_callArgs);\n\n        require(adapterIsRegistered(adapter), \"callOnIntegration: Adapter is not registered\");\n\n        // Note that expected incoming and spend assets are allowed to overlap\n        // (e.g., a fee for the incomingAsset charged in a spend asset)\n        (\n            spendAssetsHandleType_,\n            spendAssets_,\n            maxSpendAssetAmounts_,\n            expectedIncomingAssets_,\n            minIncomingAssetAmounts_\n        ) = IIntegrationAdapter(adapter).parseAssetsForMethod(selector, integrationData);\n        require(\n            spendAssets_.length == maxSpendAssetAmounts_.length,\n            \"__preProcessCoI: Spend assets arrays unequal\"\n        );\n        require(\n            expectedIncomingAssets_.length == minIncomingAssetAmounts_.length,\n            \"__preProcessCoI: Incoming assets arrays unequal\"\n        );\n        require(spendAssets_.isUniqueSet(), \"__preProcessCoI: Duplicate spend asset\");\n        require(\n            expectedIncomingAssets_.isUniqueSet(),\n            \"__preProcessCoI: Duplicate incoming asset\"\n        );\n\n        IVault vaultProxyContract = IVault(_vaultProxy);\n\n        preCallIncomingAssetBalances_ = new uint256[](expectedIncomingAssets_.length);\n        for (uint256 i = 0; i < expectedIncomingAssets_.length; i++) {\n            require(\n                expectedIncomingAssets_[i] != address(0),\n                \"__preProcessCoI: Empty incoming asset address\"\n            );\n            require(\n                minIncomingAssetAmounts_[i] > 0,\n                \"__preProcessCoI: minIncomingAssetAmount must be >0\"\n            );\n            require(\n                __isSupportedAsset(expectedIncomingAssets_[i]),\n                \"__preProcessCoI: Non-receivable incoming asset\"\n            );\n\n            // Get pre-call balance of each incoming asset.\n            // If the asset is not tracked by the fund, allow the balance to default to 0.\n            if (vaultProxyContract.isTrackedAsset(expectedIncomingAssets_[i])) {\n                // We do not require incoming asset finality, but we attempt to finalize so that\n                // the final incoming asset amount is more accurate. There is no need to finalize\n                // post-tx.\n                preCallIncomingAssetBalances_[i] = __finalizeIfSynthAndGetAssetBalance(\n                    _vaultProxy,\n                    expectedIncomingAssets_[i],\n                    false\n                );\n            }\n        }\n\n        // Get pre-call balances of spend assets and grant approvals to adapter\n        preCallSpendAssetBalances_ = new uint256[](spendAssets_.length);\n        for (uint256 i = 0; i < spendAssets_.length; i++) {\n            require(spendAssets_[i] != address(0), \"__preProcessCoI: Empty spend asset\");\n            require(maxSpendAssetAmounts_[i] > 0, \"__preProcessCoI: Empty max spend asset amount\");\n            // A spend asset must either be a tracked asset of the fund or a supported asset,\n            // in order to prevent seeding the fund with a malicious token and performing arbitrary\n            // actions within an adapter.\n            require(\n                vaultProxyContract.isTrackedAsset(spendAssets_[i]) ||\n                    __isSupportedAsset(spendAssets_[i]),\n                \"__preProcessCoI: Non-spendable spend asset\"\n            );\n\n            // If spend asset is also an incoming asset, no need to record its balance\n            if (!expectedIncomingAssets_.contains(spendAssets_[i])) {\n                // By requiring spend asset finality before CoI, we will know whether or\n                // not the asset balance was entirely spent during the call. There is no need\n                // to finalize post-tx.\n                preCallSpendAssetBalances_[i] = __finalizeIfSynthAndGetAssetBalance(\n                    _vaultProxy,\n                    spendAssets_[i],\n                    true\n                );\n            }\n\n            // Grant spend assets access to the adapter.\n            // Note that spendAssets_ is already asserted to a unique set.\n            if (spendAssetsHandleType_ == SpendAssetsHandleType.Approve) {\n                // Use exact approve amount rather than increasing allowances,\n                // because all adapters finish their actions atomically.\n                __approveAssetSpender(\n                    msg.sender,\n                    spendAssets_[i],\n                    adapter,\n                    maxSpendAssetAmounts_[i]\n                );\n            } else if (spendAssetsHandleType_ == SpendAssetsHandleType.Transfer) {\n                __withdrawAssetTo(msg.sender, spendAssets_[i], adapter, maxSpendAssetAmounts_[i]);\n            } else if (spendAssetsHandleType_ == SpendAssetsHandleType.Remove) {\n                __removeTrackedAsset(msg.sender, spendAssets_[i]);\n            }\n        }\n    }\n\n    /// @dev Helper for the actions to take on external contracts after executing CoI\n    function __postCoIHook(\n        address _adapter,\n        bytes4 _selector,\n        address[] memory _incomingAssets,\n        uint256[] memory _incomingAssetAmounts,\n        address[] memory _outgoingAssets,\n        uint256[] memory _outgoingAssetAmounts\n    ) private {\n        IPolicyManager(POLICY_MANAGER).validatePolicies(\n            msg.sender,\n            IPolicyManager.PolicyHook.PostCallOnIntegration,\n            abi.encode(\n                _adapter,\n                _selector,\n                _incomingAssets,\n                _incomingAssetAmounts,\n                _outgoingAssets,\n                _outgoingAssetAmounts\n            )\n        );\n    }\n\n    /// @dev Helper to reconcile and format incoming and outgoing assets after executing CoI\n    function __postProcessCoI(\n        address _vaultProxy,\n        address[] memory _expectedIncomingAssets,\n        uint256[] memory _preCallIncomingAssetBalances,\n        uint256[] memory _minIncomingAssetAmounts,\n        SpendAssetsHandleType _spendAssetsHandleType,\n        address[] memory _spendAssets,\n        uint256[] memory _maxSpendAssetAmounts,\n        uint256[] memory _preCallSpendAssetBalances\n    )\n        private\n        returns (\n            address[] memory incomingAssets_,\n            uint256[] memory incomingAssetAmounts_,\n            address[] memory outgoingAssets_,\n            uint256[] memory outgoingAssetAmounts_\n        )\n    {\n        address[] memory increasedSpendAssets;\n        uint256[] memory increasedSpendAssetAmounts;\n        (\n            outgoingAssets_,\n            outgoingAssetAmounts_,\n            increasedSpendAssets,\n            increasedSpendAssetAmounts\n        ) = __reconcileCoISpendAssets(\n            _vaultProxy,\n            _spendAssetsHandleType,\n            _spendAssets,\n            _maxSpendAssetAmounts,\n            _preCallSpendAssetBalances\n        );\n\n        (incomingAssets_, incomingAssetAmounts_) = __reconcileCoIIncomingAssets(\n            _vaultProxy,\n            _expectedIncomingAssets,\n            _preCallIncomingAssetBalances,\n            _minIncomingAssetAmounts,\n            increasedSpendAssets,\n            increasedSpendAssetAmounts\n        );\n\n        return (incomingAssets_, incomingAssetAmounts_, outgoingAssets_, outgoingAssetAmounts_);\n    }\n\n    /// @dev Helper to process incoming asset balance changes.\n    /// See __reconcileCoISpendAssets() for explanation on \"increasedSpendAssets\".\n    function __reconcileCoIIncomingAssets(\n        address _vaultProxy,\n        address[] memory _expectedIncomingAssets,\n        uint256[] memory _preCallIncomingAssetBalances,\n        uint256[] memory _minIncomingAssetAmounts,\n        address[] memory _increasedSpendAssets,\n        uint256[] memory _increasedSpendAssetAmounts\n    ) private returns (address[] memory incomingAssets_, uint256[] memory incomingAssetAmounts_) {\n        // Incoming assets = expected incoming assets + spend assets with increased balances\n        uint256 incomingAssetsCount = _expectedIncomingAssets.length.add(\n            _increasedSpendAssets.length\n        );\n\n        // Calculate and validate incoming asset amounts\n        incomingAssets_ = new address[](incomingAssetsCount);\n        incomingAssetAmounts_ = new uint256[](incomingAssetsCount);\n        for (uint256 i = 0; i < _expectedIncomingAssets.length; i++) {\n            uint256 balanceDiff = __getVaultAssetBalance(_vaultProxy, _expectedIncomingAssets[i])\n                .sub(_preCallIncomingAssetBalances[i]);\n            require(\n                balanceDiff >= _minIncomingAssetAmounts[i],\n                \"__reconcileCoIAssets: Received incoming asset less than expected\"\n            );\n\n            // Even if the asset's previous balance was >0, it might not have been tracked\n            __addTrackedAsset(msg.sender, _expectedIncomingAssets[i]);\n\n            incomingAssets_[i] = _expectedIncomingAssets[i];\n            incomingAssetAmounts_[i] = balanceDiff;\n        }\n\n        // Append increaseSpendAssets to incomingAsset vars\n        if (_increasedSpendAssets.length > 0) {\n            uint256 incomingAssetIndex = _expectedIncomingAssets.length;\n            for (uint256 i = 0; i < _increasedSpendAssets.length; i++) {\n                incomingAssets_[incomingAssetIndex] = _increasedSpendAssets[i];\n                incomingAssetAmounts_[incomingAssetIndex] = _increasedSpendAssetAmounts[i];\n                incomingAssetIndex++;\n            }\n        }\n\n        return (incomingAssets_, incomingAssetAmounts_);\n    }\n\n    /// @dev Helper to process spend asset balance changes.\n    /// \"outgoingAssets\" are the spend assets with a decrease in balance.\n    /// \"increasedSpendAssets\" are the spend assets with an unexpected increase in balance.\n    /// For example, \"increasedSpendAssets\" can occur if an adapter has a pre-balance of\n    /// the spendAsset, which would be transferred to the fund at the end of the tx.\n    function __reconcileCoISpendAssets(\n        address _vaultProxy,\n        SpendAssetsHandleType _spendAssetsHandleType,\n        address[] memory _spendAssets,\n        uint256[] memory _maxSpendAssetAmounts,\n        uint256[] memory _preCallSpendAssetBalances\n    )\n        private\n        returns (\n            address[] memory outgoingAssets_,\n            uint256[] memory outgoingAssetAmounts_,\n            address[] memory increasedSpendAssets_,\n            uint256[] memory increasedSpendAssetAmounts_\n        )\n    {\n        // Determine spend asset balance changes\n        uint256[] memory postCallSpendAssetBalances = new uint256[](_spendAssets.length);\n        uint256 outgoingAssetsCount;\n        uint256 increasedSpendAssetsCount;\n        for (uint256 i = 0; i < _spendAssets.length; i++) {\n            // If spend asset's initial balance is 0, then it is an incoming asset\n            if (_preCallSpendAssetBalances[i] == 0) {\n                continue;\n            }\n\n            // Handle SpendAssetsHandleType.Remove separately\n            if (_spendAssetsHandleType == SpendAssetsHandleType.Remove) {\n                outgoingAssetsCount++;\n                continue;\n            }\n\n            // Determine if the asset is outgoing or incoming, and store the post-balance for later use\n            postCallSpendAssetBalances[i] = __getVaultAssetBalance(_vaultProxy, _spendAssets[i]);\n            // If the pre- and post- balances are equal, then the asset is neither incoming nor outgoing\n            if (postCallSpendAssetBalances[i] < _preCallSpendAssetBalances[i]) {\n                outgoingAssetsCount++;\n            } else if (postCallSpendAssetBalances[i] > _preCallSpendAssetBalances[i]) {\n                increasedSpendAssetsCount++;\n            }\n        }\n\n        // Format outgoingAssets and increasedSpendAssets (spend assets with unexpected increase in balance)\n        outgoingAssets_ = new address[](outgoingAssetsCount);\n        outgoingAssetAmounts_ = new uint256[](outgoingAssetsCount);\n        increasedSpendAssets_ = new address[](increasedSpendAssetsCount);\n        increasedSpendAssetAmounts_ = new uint256[](increasedSpendAssetsCount);\n        uint256 outgoingAssetsIndex;\n        uint256 increasedSpendAssetsIndex;\n        for (uint256 i = 0; i < _spendAssets.length; i++) {\n            // If spend asset's initial balance is 0, then it is an incoming asset.\n            if (_preCallSpendAssetBalances[i] == 0) {\n                continue;\n            }\n\n            // Handle SpendAssetsHandleType.Remove separately.\n            // No need to validate the max spend asset amount.\n            if (_spendAssetsHandleType == SpendAssetsHandleType.Remove) {\n                outgoingAssets_[outgoingAssetsIndex] = _spendAssets[i];\n                outgoingAssetAmounts_[outgoingAssetsIndex] = _preCallSpendAssetBalances[i];\n                outgoingAssetsIndex++;\n                continue;\n            }\n\n            // If the pre- and post- balances are equal, then the asset is neither incoming nor outgoing\n            if (postCallSpendAssetBalances[i] < _preCallSpendAssetBalances[i]) {\n                if (postCallSpendAssetBalances[i] == 0) {\n                    __removeTrackedAsset(msg.sender, _spendAssets[i]);\n                    outgoingAssetAmounts_[outgoingAssetsIndex] = _preCallSpendAssetBalances[i];\n                } else {\n                    outgoingAssetAmounts_[outgoingAssetsIndex] = _preCallSpendAssetBalances[i].sub(\n                        postCallSpendAssetBalances[i]\n                    );\n                }\n                require(\n                    outgoingAssetAmounts_[outgoingAssetsIndex] <= _maxSpendAssetAmounts[i],\n                    \"__reconcileCoISpendAssets: Spent amount greater than expected\"\n                );\n\n                outgoingAssets_[outgoingAssetsIndex] = _spendAssets[i];\n                outgoingAssetsIndex++;\n            } else if (postCallSpendAssetBalances[i] > _preCallSpendAssetBalances[i]) {\n                increasedSpendAssetAmounts_[increasedSpendAssetsIndex] = postCallSpendAssetBalances[i]\n                    .sub(_preCallSpendAssetBalances[i]);\n                increasedSpendAssets_[increasedSpendAssetsIndex] = _spendAssets[i];\n                increasedSpendAssetsIndex++;\n            }\n        }\n\n        return (\n            outgoingAssets_,\n            outgoingAssetAmounts_,\n            increasedSpendAssets_,\n            increasedSpendAssetAmounts_\n        );\n    }\n\n    ///////////////////////////\n    // INTEGRATIONS REGISTRY //\n    ///////////////////////////\n\n    /// @notice Remove integration adapters from the list of registered adapters\n    /// @param _adapters Addresses of adapters to be deregistered\n    function deregisterAdapters(address[] calldata _adapters) external onlyFundDeployerOwner {\n        require(_adapters.length > 0, \"deregisterAdapters: _adapters cannot be empty\");\n\n        for (uint256 i; i < _adapters.length; i++) {\n            require(\n                adapterIsRegistered(_adapters[i]),\n                \"deregisterAdapters: Adapter is not registered\"\n            );\n\n            registeredAdapters.remove(_adapters[i]);\n\n            emit AdapterDeregistered(_adapters[i], IIntegrationAdapter(_adapters[i]).identifier());\n        }\n    }\n\n    /// @notice Add integration adapters to the list of registered adapters\n    /// @param _adapters Addresses of adapters to be registered\n    function registerAdapters(address[] calldata _adapters) external onlyFundDeployerOwner {\n        require(_adapters.length > 0, \"registerAdapters: _adapters cannot be empty\");\n\n        for (uint256 i; i < _adapters.length; i++) {\n            require(_adapters[i] != address(0), \"registerAdapters: Adapter cannot be empty\");\n\n            require(\n                !adapterIsRegistered(_adapters[i]),\n                \"registerAdapters: Adapter already registered\"\n            );\n\n            registeredAdapters.add(_adapters[i]);\n\n            emit AdapterRegistered(_adapters[i], IIntegrationAdapter(_adapters[i]).identifier());\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Checks if an integration adapter is registered\n    /// @param _adapter The adapter to check\n    /// @return isRegistered_ True if the adapter is registered\n    function adapterIsRegistered(address _adapter) public view returns (bool isRegistered_) {\n        return registeredAdapters.contains(_adapter);\n    }\n\n    /// @notice Gets the `DERIVATIVE_PRICE_FEED` variable\n    /// @return derivativePriceFeed_ The `DERIVATIVE_PRICE_FEED` variable value\n    function getDerivativePriceFeed() external view returns (address derivativePriceFeed_) {\n        return DERIVATIVE_PRICE_FEED;\n    }\n\n    /// @notice Gets the `POLICY_MANAGER` variable\n    /// @return policyManager_ The `POLICY_MANAGER` variable value\n    function getPolicyManager() external view returns (address policyManager_) {\n        return POLICY_MANAGER;\n    }\n\n    /// @notice Gets the `PRIMITIVE_PRICE_FEED` variable\n    /// @return primitivePriceFeed_ The `PRIMITIVE_PRICE_FEED` variable value\n    function getPrimitivePriceFeed() external view returns (address primitivePriceFeed_) {\n        return PRIMITIVE_PRICE_FEED;\n    }\n\n    /// @notice Gets all registered integration adapters\n    /// @return registeredAdaptersArray_ A list of all registered integration adapters\n    function getRegisteredAdapters()\n        external\n        view\n        returns (address[] memory registeredAdaptersArray_)\n    {\n        registeredAdaptersArray_ = new address[](registeredAdapters.length());\n        for (uint256 i = 0; i < registeredAdaptersArray_.length; i++) {\n            registeredAdaptersArray_[i] = registeredAdapters.at(i);\n        }\n\n        return registeredAdaptersArray_;\n    }\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/SynthetixAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../infrastructure/price-feeds/derivatives/feeds/SynthetixPriceFeed.sol\";\nimport \"../../../../interfaces/ISynthetix.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title SynthetixAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for interacting with Synthetix\ncontract SynthetixAdapter is AdapterBase {\n    address private immutable ORIGINATOR;\n    address private immutable SYNTHETIX;\n    address private immutable SYNTHETIX_PRICE_FEED;\n    bytes32 private immutable TRACKING_CODE;\n\n    constructor(\n        address _integrationManager,\n        address _synthetixPriceFeed,\n        address _originator,\n        address _synthetix,\n        bytes32 _trackingCode\n    ) public AdapterBase(_integrationManager) {\n        ORIGINATOR = _originator;\n        SYNTHETIX = _synthetix;\n        SYNTHETIX_PRICE_FEED = _synthetixPriceFeed;\n        TRACKING_CODE = _trackingCode;\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ An identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"SYNTHETIX\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        require(_selector == TAKE_ORDER_SELECTOR, \"parseAssetsForMethod: _selector invalid\");\n\n        (\n            address incomingAsset,\n            uint256 minIncomingAssetAmount,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        spendAssets_ = new address[](1);\n        spendAssets_[0] = outgoingAsset;\n        spendAssetAmounts_ = new uint256[](1);\n        spendAssetAmounts_[0] = outgoingAssetAmount;\n\n        incomingAssets_ = new address[](1);\n        incomingAssets_[0] = incomingAsset;\n        minIncomingAssetAmounts_ = new uint256[](1);\n        minIncomingAssetAmounts_[0] = minIncomingAssetAmount;\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.None,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Trades assets on Synthetix\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    function takeOrder(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata\n    ) external onlyIntegrationManager {\n        (\n            address incomingAsset,\n            ,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        address[] memory synths = new address[](2);\n        synths[0] = outgoingAsset;\n        synths[1] = incomingAsset;\n\n        bytes32[] memory currencyKeys = SynthetixPriceFeed(SYNTHETIX_PRICE_FEED)\n            .getCurrencyKeysForSynths(synths);\n\n        ISynthetix(SYNTHETIX).exchangeOnBehalfWithTracking(\n            _vaultProxy,\n            currencyKeys[0],\n            outgoingAssetAmount,\n            currencyKeys[1],\n            ORIGINATOR,\n            TRACKING_CODE\n        );\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode the encoded call arguments\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address incomingAsset_,\n            uint256 minIncomingAssetAmount_,\n            address outgoingAsset_,\n            uint256 outgoingAssetAmount_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (address, uint256, address, uint256));\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `ORIGINATOR` variable\n    /// @return originator_ The `ORIGINATOR` variable value\n    function getOriginator() external view returns (address originator_) {\n        return ORIGINATOR;\n    }\n\n    /// @notice Gets the `SYNTHETIX` variable\n    /// @return synthetix_ The `SYNTHETIX` variable value\n    function getSynthetix() external view returns (address synthetix_) {\n        return SYNTHETIX;\n    }\n\n    /// @notice Gets the `SYNTHETIX_PRICE_FEED` variable\n    /// @return synthetixPriceFeed_ The `SYNTHETIX_PRICE_FEED` variable value\n    function getSynthetixPriceFeed() external view returns (address synthetixPriceFeed_) {\n        return SYNTHETIX_PRICE_FEED;\n    }\n\n    /// @notice Gets the `TRACKING_CODE` variable\n    /// @return trackingCode_ The `TRACKING_CODE` variable value\n    function getTrackingCode() external view returns (bytes32 trackingCode_) {\n        return TRACKING_CODE;\n    }\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/primitives/ChainlinkPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../../interfaces/IChainlinkAggregator.sol\";\nimport \"../../utils/DispatcherOwnerMixin.sol\";\nimport \"./IPrimitivePriceFeed.sol\";\n\n/// @title ChainlinkPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A price feed that uses Chainlink oracles as price sources\ncontract ChainlinkPriceFeed is IPrimitivePriceFeed, DispatcherOwnerMixin {\n    using SafeMath for uint256;\n\n    event EthUsdAggregatorSet(address prevEthUsdAggregator, address nextEthUsdAggregator);\n\n    event PrimitiveAdded(\n        address indexed primitive,\n        address aggregator,\n        RateAsset rateAsset,\n        uint256 unit\n    );\n\n    event PrimitiveRemoved(address indexed primitive);\n\n    event PrimitiveUpdated(\n        address indexed primitive,\n        address prevAggregator,\n        address nextAggregator\n    );\n\n    event StalePrimitiveRemoved(address indexed primitive);\n\n    event StaleRateThresholdSet(uint256 prevStaleRateThreshold, uint256 nextStaleRateThreshold);\n\n    enum RateAsset {ETH, USD}\n\n    struct AggregatorInfo {\n        address aggregator;\n        RateAsset rateAsset;\n    }\n\n    uint256 private constant ETH_UNIT = 10**18;\n    address private immutable WETH_TOKEN;\n\n    address private ethUsdAggregator;\n    uint256 private staleRateThreshold;\n    mapping(address => AggregatorInfo) private primitiveToAggregatorInfo;\n    mapping(address => uint256) private primitiveToUnit;\n\n    constructor(\n        address _dispatcher,\n        address _wethToken,\n        address _ethUsdAggregator,\n        address[] memory _primitives,\n        address[] memory _aggregators,\n        RateAsset[] memory _rateAssets\n    ) public DispatcherOwnerMixin(_dispatcher) {\n        WETH_TOKEN = _wethToken;\n        staleRateThreshold = 25 hours; // 24 hour heartbeat + 1hr buffer\n        __setEthUsdAggregator(_ethUsdAggregator);\n        if (_primitives.length > 0) {\n            __addPrimitives(_primitives, _aggregators, _rateAssets);\n        }\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Calculates the value of a base asset in terms of a quote asset (using a canonical rate)\n    /// @param _baseAsset The base asset\n    /// @param _baseAssetAmount The base asset amount to convert\n    /// @param _quoteAsset The quote asset\n    /// @return quoteAssetAmount_ The equivalent quote asset amount\n    /// @return isValid_ True if the rates used in calculations are deemed valid\n    function calcCanonicalValue(\n        address _baseAsset,\n        uint256 _baseAssetAmount,\n        address _quoteAsset\n    ) public view override returns (uint256 quoteAssetAmount_, bool isValid_) {\n        // Case where _baseAsset == _quoteAsset is handled by ValueInterpreter\n\n        int256 baseAssetRate = __getLatestRateData(_baseAsset);\n        if (baseAssetRate <= 0) {\n            return (0, false);\n        }\n\n        int256 quoteAssetRate = __getLatestRateData(_quoteAsset);\n        if (quoteAssetRate <= 0) {\n            return (0, false);\n        }\n\n        (quoteAssetAmount_, isValid_) = __calcConversionAmount(\n            _baseAsset,\n            _baseAssetAmount,\n            uint256(baseAssetRate),\n            _quoteAsset,\n            uint256(quoteAssetRate)\n        );\n\n        return (quoteAssetAmount_, isValid_);\n    }\n\n    /// @notice Calculates the value of a base asset in terms of a quote asset (using a live rate)\n    /// @param _baseAsset The base asset\n    /// @param _baseAssetAmount The base asset amount to convert\n    /// @param _quoteAsset The quote asset\n    /// @return quoteAssetAmount_ The equivalent quote asset amount\n    /// @return isValid_ True if the rates used in calculations are deemed valid\n    /// @dev Live and canonical values are the same for Chainlink\n    function calcLiveValue(\n        address _baseAsset,\n        uint256 _baseAssetAmount,\n        address _quoteAsset\n    ) external view override returns (uint256 quoteAssetAmount_, bool isValid_) {\n        return calcCanonicalValue(_baseAsset, _baseAssetAmount, _quoteAsset);\n    }\n\n    /// @notice Checks whether an asset is a supported primitive of the price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is a supported primitive\n    function isSupportedAsset(address _asset) external view override returns (bool isSupported_) {\n        return _asset == WETH_TOKEN || primitiveToAggregatorInfo[_asset].aggregator != address(0);\n    }\n\n    /// @notice Sets the `ehUsdAggregator` variable value\n    /// @param _nextEthUsdAggregator The `ehUsdAggregator` value to set\n    function setEthUsdAggregator(address _nextEthUsdAggregator) external onlyDispatcherOwner {\n        __setEthUsdAggregator(_nextEthUsdAggregator);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to convert an amount from a _baseAsset to a _quoteAsset\n    function __calcConversionAmount(\n        address _baseAsset,\n        uint256 _baseAssetAmount,\n        uint256 _baseAssetRate,\n        address _quoteAsset,\n        uint256 _quoteAssetRate\n    ) private view returns (uint256 quoteAssetAmount_, bool isValid_) {\n        RateAsset baseAssetRateAsset = getRateAssetForPrimitive(_baseAsset);\n        RateAsset quoteAssetRateAsset = getRateAssetForPrimitive(_quoteAsset);\n        uint256 baseAssetUnit = getUnitForPrimitive(_baseAsset);\n        uint256 quoteAssetUnit = getUnitForPrimitive(_quoteAsset);\n\n        // If rates are both in ETH or both in USD\n        if (baseAssetRateAsset == quoteAssetRateAsset) {\n            return (\n                __calcConversionAmountSameRateAsset(\n                    _baseAssetAmount,\n                    baseAssetUnit,\n                    _baseAssetRate,\n                    quoteAssetUnit,\n                    _quoteAssetRate\n                ),\n                true\n            );\n        }\n\n        int256 ethPerUsdRate = IChainlinkAggregator(ethUsdAggregator).latestAnswer();\n        if (ethPerUsdRate <= 0) {\n            return (0, false);\n        }\n\n        // If _baseAsset's rate is in ETH and _quoteAsset's rate is in USD\n        if (baseAssetRateAsset == RateAsset.ETH) {\n            return (\n                __calcConversionAmountEthRateAssetToUsdRateAsset(\n                    _baseAssetAmount,\n                    baseAssetUnit,\n                    _baseAssetRate,\n                    quoteAssetUnit,\n                    _quoteAssetRate,\n                    uint256(ethPerUsdRate)\n                ),\n                true\n            );\n        }\n\n        // If _baseAsset's rate is in USD and _quoteAsset's rate is in ETH\n        return (\n            __calcConversionAmountUsdRateAssetToEthRateAsset(\n                _baseAssetAmount,\n                baseAssetUnit,\n                _baseAssetRate,\n                quoteAssetUnit,\n                _quoteAssetRate,\n                uint256(ethPerUsdRate)\n            ),\n            true\n        );\n    }\n\n    /// @dev Helper to convert amounts where the base asset has an ETH rate and the quote asset has a USD rate\n    function __calcConversionAmountEthRateAssetToUsdRateAsset(\n        uint256 _baseAssetAmount,\n        uint256 _baseAssetUnit,\n        uint256 _baseAssetRate,\n        uint256 _quoteAssetUnit,\n        uint256 _quoteAssetRate,\n        uint256 _ethPerUsdRate\n    ) private pure returns (uint256 quoteAssetAmount_) {\n        // Only allows two consecutive multiplication operations to avoid potential overflow.\n        // Intermediate step needed to resolve stack-too-deep error.\n        uint256 intermediateStep = _baseAssetAmount.mul(_baseAssetRate).mul(_ethPerUsdRate).div(\n            ETH_UNIT\n        );\n\n        return intermediateStep.mul(_quoteAssetUnit).div(_baseAssetUnit).div(_quoteAssetRate);\n    }\n\n    /// @dev Helper to convert amounts where base and quote assets both have ETH rates or both have USD rates\n    function __calcConversionAmountSameRateAsset(\n        uint256 _baseAssetAmount,\n        uint256 _baseAssetUnit,\n        uint256 _baseAssetRate,\n        uint256 _quoteAssetUnit,\n        uint256 _quoteAssetRate\n    ) private pure returns (uint256 quoteAssetAmount_) {\n        // Only allows two consecutive multiplication operations to avoid potential overflow\n        return\n            _baseAssetAmount.mul(_baseAssetRate).mul(_quoteAssetUnit).div(\n                _baseAssetUnit.mul(_quoteAssetRate)\n            );\n    }\n\n    /// @dev Helper to convert amounts where the base asset has a USD rate and the quote asset has an ETH rate\n    function __calcConversionAmountUsdRateAssetToEthRateAsset(\n        uint256 _baseAssetAmount,\n        uint256 _baseAssetUnit,\n        uint256 _baseAssetRate,\n        uint256 _quoteAssetUnit,\n        uint256 _quoteAssetRate,\n        uint256 _ethPerUsdRate\n    ) private pure returns (uint256 quoteAssetAmount_) {\n        // Only allows two consecutive multiplication operations to avoid potential overflow\n        // Intermediate step needed to resolve stack-too-deep error.\n        uint256 intermediateStep = _baseAssetAmount.mul(_baseAssetRate).mul(_quoteAssetUnit).div(\n            _ethPerUsdRate\n        );\n\n        return intermediateStep.mul(ETH_UNIT).div(_baseAssetUnit).div(_quoteAssetRate);\n    }\n\n    /// @dev Helper to get the latest rate for a given primitive\n    function __getLatestRateData(address _primitive) private view returns (int256 rate_) {\n        if (_primitive == WETH_TOKEN) {\n            return int256(ETH_UNIT);\n        }\n\n        address aggregator = primitiveToAggregatorInfo[_primitive].aggregator;\n        require(aggregator != address(0), \"__getLatestRateData: Primitive does not exist\");\n\n        return IChainlinkAggregator(aggregator).latestAnswer();\n    }\n\n    /// @dev Helper to set the `ethUsdAggregator` value\n    function __setEthUsdAggregator(address _nextEthUsdAggregator) private {\n        address prevEthUsdAggregator = ethUsdAggregator;\n        require(\n            _nextEthUsdAggregator != prevEthUsdAggregator,\n            \"__setEthUsdAggregator: Value already set\"\n        );\n\n        __validateAggregator(_nextEthUsdAggregator);\n\n        ethUsdAggregator = _nextEthUsdAggregator;\n\n        emit EthUsdAggregatorSet(prevEthUsdAggregator, _nextEthUsdAggregator);\n    }\n\n    /////////////////////////\n    // PRIMITIVES REGISTRY //\n    /////////////////////////\n\n    /// @notice Adds a list of primitives with the given aggregator and rateAsset values\n    /// @param _primitives The primitives to add\n    /// @param _aggregators The ordered aggregators corresponding to the list of _primitives\n    /// @param _rateAssets The ordered rate assets corresponding to the list of _primitives\n    function addPrimitives(\n        address[] calldata _primitives,\n        address[] calldata _aggregators,\n        RateAsset[] calldata _rateAssets\n    ) external onlyDispatcherOwner {\n        require(_primitives.length > 0, \"addPrimitives: _primitives cannot be empty\");\n\n        __addPrimitives(_primitives, _aggregators, _rateAssets);\n    }\n\n    /// @notice Removes a list of primitives from the feed\n    /// @param _primitives The primitives to remove\n    function removePrimitives(address[] calldata _primitives) external onlyDispatcherOwner {\n        require(_primitives.length > 0, \"removePrimitives: _primitives cannot be empty\");\n\n        for (uint256 i; i < _primitives.length; i++) {\n            require(\n                primitiveToAggregatorInfo[_primitives[i]].aggregator != address(0),\n                \"removePrimitives: Primitive not yet added\"\n            );\n\n            delete primitiveToAggregatorInfo[_primitives[i]];\n            delete primitiveToUnit[_primitives[i]];\n\n            emit PrimitiveRemoved(_primitives[i]);\n        }\n    }\n\n    /// @notice Removes stale primitives from the feed\n    /// @param _primitives The stale primitives to remove\n    /// @dev Callable by anybody\n    function removeStalePrimitives(address[] calldata _primitives) external {\n        require(_primitives.length > 0, \"removeStalePrimitives: _primitives cannot be empty\");\n\n        for (uint256 i; i < _primitives.length; i++) {\n            address aggregatorAddress = primitiveToAggregatorInfo[_primitives[i]].aggregator;\n            require(aggregatorAddress != address(0), \"removeStalePrimitives: Invalid primitive\");\n            require(rateIsStale(aggregatorAddress), \"removeStalePrimitives: Rate is not stale\");\n\n            delete primitiveToAggregatorInfo[_primitives[i]];\n            delete primitiveToUnit[_primitives[i]];\n\n            emit StalePrimitiveRemoved(_primitives[i]);\n        }\n    }\n\n    /// @notice Sets the `staleRateThreshold` variable\n    /// @param _nextStaleRateThreshold The next `staleRateThreshold` value\n    function setStaleRateThreshold(uint256 _nextStaleRateThreshold) external onlyDispatcherOwner {\n        uint256 prevStaleRateThreshold = staleRateThreshold;\n        require(\n            _nextStaleRateThreshold != prevStaleRateThreshold,\n            \"__setStaleRateThreshold: Value already set\"\n        );\n\n        staleRateThreshold = _nextStaleRateThreshold;\n\n        emit StaleRateThresholdSet(prevStaleRateThreshold, _nextStaleRateThreshold);\n    }\n\n    /// @notice Updates the aggregators for given primitives\n    /// @param _primitives The primitives to update\n    /// @param _aggregators The ordered aggregators corresponding to the list of _primitives\n    function updatePrimitives(address[] calldata _primitives, address[] calldata _aggregators)\n        external\n        onlyDispatcherOwner\n    {\n        require(_primitives.length > 0, \"updatePrimitives: _primitives cannot be empty\");\n        require(\n            _primitives.length == _aggregators.length,\n            \"updatePrimitives: Unequal _primitives and _aggregators array lengths\"\n        );\n\n        for (uint256 i; i < _primitives.length; i++) {\n            address prevAggregator = primitiveToAggregatorInfo[_primitives[i]].aggregator;\n            require(prevAggregator != address(0), \"updatePrimitives: Primitive not yet added\");\n            require(_aggregators[i] != prevAggregator, \"updatePrimitives: Value already set\");\n\n            __validateAggregator(_aggregators[i]);\n\n            primitiveToAggregatorInfo[_primitives[i]].aggregator = _aggregators[i];\n\n            emit PrimitiveUpdated(_primitives[i], prevAggregator, _aggregators[i]);\n        }\n    }\n\n    /// @notice Checks whether the current rate is considered stale for the specified aggregator\n    /// @param _aggregator The Chainlink aggregator of which to check staleness\n    /// @return rateIsStale_ True if the rate is considered stale\n    function rateIsStale(address _aggregator) public view returns (bool rateIsStale_) {\n        return\n            IChainlinkAggregator(_aggregator).latestTimestamp() <\n            block.timestamp.sub(staleRateThreshold);\n    }\n\n    /// @dev Helper to add primitives to the feed\n    function __addPrimitives(\n        address[] memory _primitives,\n        address[] memory _aggregators,\n        RateAsset[] memory _rateAssets\n    ) private {\n        require(\n            _primitives.length == _aggregators.length,\n            \"__addPrimitives: Unequal _primitives and _aggregators array lengths\"\n        );\n        require(\n            _primitives.length == _rateAssets.length,\n            \"__addPrimitives: Unequal _primitives and _rateAssets array lengths\"\n        );\n\n        for (uint256 i = 0; i < _primitives.length; i++) {\n            require(\n                primitiveToAggregatorInfo[_primitives[i]].aggregator == address(0),\n                \"__addPrimitives: Value already set\"\n            );\n\n            __validateAggregator(_aggregators[i]);\n\n            primitiveToAggregatorInfo[_primitives[i]] = AggregatorInfo({\n                aggregator: _aggregators[i],\n                rateAsset: _rateAssets[i]\n            });\n\n            // Store the amount that makes up 1 unit given the asset's decimals\n            uint256 unit = 10**uint256(ERC20(_primitives[i]).decimals());\n            primitiveToUnit[_primitives[i]] = unit;\n\n            emit PrimitiveAdded(_primitives[i], _aggregators[i], _rateAssets[i], unit);\n        }\n    }\n\n    /// @dev Helper to validate an aggregator by checking its return values for the expected interface\n    function __validateAggregator(address _aggregator) private view {\n        require(_aggregator != address(0), \"__validateAggregator: Empty _aggregator\");\n\n        require(\n            IChainlinkAggregator(_aggregator).latestAnswer() > 0,\n            \"__validateAggregator: No rate detected\"\n        );\n        require(!rateIsStale(_aggregator), \"__validateAggregator: Stale rate detected\");\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the aggregatorInfo variable value for a primitive\n    /// @param _primitive The primitive asset for which to get the aggregatorInfo value\n    /// @return aggregatorInfo_ The aggregatorInfo value\n    function getAggregatorInfoForPrimitive(address _primitive)\n        external\n        view\n        returns (AggregatorInfo memory aggregatorInfo_)\n    {\n        return primitiveToAggregatorInfo[_primitive];\n    }\n\n    /// @notice Gets the `ethUsdAggregator` variable value\n    /// @return ethUsdAggregator_ The `ethUsdAggregator` variable value\n    function getEthUsdAggregator() external view returns (address ethUsdAggregator_) {\n        return ethUsdAggregator;\n    }\n\n    /// @notice Gets the `staleRateThreshold` variable value\n    /// @return staleRateThreshold_ The `staleRateThreshold` variable value\n    function getStaleRateThreshold() external view returns (uint256 staleRateThreshold_) {\n        return staleRateThreshold;\n    }\n\n    /// @notice Gets the `WETH_TOKEN` variable value\n    /// @return wethToken_ The `WETH_TOKEN` variable value\n    function getWethToken() external view returns (address wethToken_) {\n        return WETH_TOKEN;\n    }\n\n    /// @notice Gets the rateAsset variable value for a primitive\n    /// @return rateAsset_ The rateAsset variable value\n    /// @dev This isn't strictly necessary as WETH_TOKEN will be undefined and thus\n    /// the RateAsset will be the 0-position of the enum (i.e. ETH), but it makes the\n    /// behavior more explicit\n    function getRateAssetForPrimitive(address _primitive)\n        public\n        view\n        returns (RateAsset rateAsset_)\n    {\n        if (_primitive == WETH_TOKEN) {\n            return RateAsset.ETH;\n        }\n\n        return primitiveToAggregatorInfo[_primitive].rateAsset;\n    }\n\n    /// @notice Gets the unit variable value for a primitive\n    /// @return unit_ The unit variable value\n    function getUnitForPrimitive(address _primitive) public view returns (uint256 unit_) {\n        if (_primitive == WETH_TOKEN) {\n            return ETH_UNIT;\n        }\n\n        return primitiveToUnit[_primitive];\n    }\n}\n"
      },
      "contracts/mocks/prices/CentralizedRateProvider.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../release/infrastructure/value-interpreter/IValueInterpreter.sol\";\nimport \"../../release/infrastructure/price-feeds/derivatives/IAggregatedDerivativePriceFeed.sol\";\nimport \"../../release/infrastructure/price-feeds/primitives/IPrimitivePriceFeed.sol\";\n\n/// @dev This contract acts as a centralized rate provider for mocks.\n/// Suited for a dev environment, it doesn't take into account gas costs.\ncontract CentralizedRateProvider is Ownable {\n    using SafeMath for uint256;\n\n    address private immutable WETH;\n    uint256 private maxDeviationPerSender;\n\n    // Addresses are not immutable to facilitate lazy load (they're are not accessible at the mock env).\n    address private valueInterpreter;\n    address private aggregateDerivativePriceFeed;\n    address private primitivePriceFeed;\n\n    constructor(address _weth, uint256 _maxDeviationPerSender) public {\n        maxDeviationPerSender = _maxDeviationPerSender;\n        WETH = _weth;\n    }\n\n    /// @dev Calculates the value of a _baseAsset relative to a _quoteAsset.\n    /// Label to ValueInterprete's calcLiveAssetValue\n    function calcLiveAssetValue(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset\n    ) public returns (uint256 value_) {\n        uint256 baseDecimalsRate = 10**uint256(ERC20(_baseAsset).decimals());\n        uint256 quoteDecimalsRate = 10**uint256(ERC20(_quoteAsset).decimals());\n\n        // 1. Check if quote asset is a primitive. If it is, use ValueInterpreter normally.\n        if (IPrimitivePriceFeed(primitivePriceFeed).isSupportedAsset(_quoteAsset)) {\n            (value_, ) = IValueInterpreter(valueInterpreter).calcLiveAssetValue(\n                _baseAsset,\n                _amount,\n                _quoteAsset\n            );\n            return value_;\n        }\n\n        // 2. Otherwise, check if base asset is a primitive, and use inverse rate from Value Interpreter.\n        if (IPrimitivePriceFeed(primitivePriceFeed).isSupportedAsset(_baseAsset)) {\n            (uint256 inverseRate, ) = IValueInterpreter(valueInterpreter).calcLiveAssetValue(\n                _quoteAsset,\n                10**uint256(ERC20(_quoteAsset).decimals()),\n                _baseAsset\n            );\n\n            uint256 rate = uint256(baseDecimalsRate).mul(quoteDecimalsRate).div(inverseRate);\n\n            value_ = _amount.mul(rate).div(baseDecimalsRate);\n            return value_;\n        }\n\n        // 3. If both assets are derivatives, calculate the rate against ETH.\n        (uint256 baseToWeth, ) = IValueInterpreter(valueInterpreter).calcLiveAssetValue(\n            _baseAsset,\n            baseDecimalsRate,\n            WETH\n        );\n\n        (uint256 quoteToWeth, ) = IValueInterpreter(valueInterpreter).calcLiveAssetValue(\n            _quoteAsset,\n            quoteDecimalsRate,\n            WETH\n        );\n\n        value_ = _amount.mul(baseToWeth).mul(quoteDecimalsRate).div(quoteToWeth).div(\n            baseDecimalsRate\n        );\n        return value_;\n    }\n\n    /// @dev Calculates a randomized live value of an asset\n    /// Aggregation of two randomization seeds: msg.sender, and by block.number.\n    function calcLiveAssetValueRandomized(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset,\n        uint256 _maxDeviationPerBlock\n    ) external returns (uint256 value_) {\n        uint256 liveAssetValue = calcLiveAssetValue(_baseAsset, _amount, _quoteAsset);\n\n        // Range [liveAssetValue * (1 - _blockNumberDeviation), liveAssetValue * (1 + _blockNumberDeviation)]\n        uint256 senderRandomizedValue_ = __calcValueRandomizedByAddress(\n            liveAssetValue,\n            msg.sender,\n            maxDeviationPerSender\n        );\n\n        // Range [liveAssetValue * (1 - _maxDeviationPerBlock - maxDeviationPerSender), liveAssetValue * (1 + _maxDeviationPerBlock + maxDeviationPerSender)]\n        value_ = __calcValueRandomizedByUint(\n            senderRandomizedValue_,\n            block.number,\n            _maxDeviationPerBlock\n        );\n\n        return value_;\n    }\n\n    /// @dev Calculates the live value of an asset including a grade of pseudo randomization, using msg.sender as the source of randomness\n    function calcLiveAssetValueRandomizedByBlockNumber(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset,\n        uint256 _maxDeviationPerBlock\n    ) external returns (uint256 value_) {\n        uint256 liveAssetValue = calcLiveAssetValue(_baseAsset, _amount, _quoteAsset);\n\n        value_ = __calcValueRandomizedByUint(liveAssetValue, block.number, _maxDeviationPerBlock);\n\n        return value_;\n    }\n\n    /// @dev Calculates the live value of an asset including a grade of pseudo-randomization, using `block.number` as the source of randomness\n    function calcLiveAssetValueRandomizedBySender(\n        address _baseAsset,\n        uint256 _amount,\n        address _quoteAsset\n    ) external returns (uint256 value_) {\n        uint256 liveAssetValue = calcLiveAssetValue(_baseAsset, _amount, _quoteAsset);\n\n        value_ = __calcValueRandomizedByAddress(liveAssetValue, msg.sender, maxDeviationPerSender);\n\n        return value_;\n    }\n\n    function setMaxDeviationPerSender(uint256 _maxDeviationPerSender) external onlyOwner {\n        maxDeviationPerSender = _maxDeviationPerSender;\n    }\n\n    /// @dev Connector from release environment, inject price variables into the provider.\n    function setReleasePriceAddresses(\n        address _valueInterpreter,\n        address _aggregateDerivativePriceFeed,\n        address _primitivePriceFeed\n    ) external onlyOwner {\n        valueInterpreter = _valueInterpreter;\n        aggregateDerivativePriceFeed = _aggregateDerivativePriceFeed;\n        primitivePriceFeed = _primitivePriceFeed;\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Calculates a a pseudo-randomized value as a seed an address\n    function __calcValueRandomizedByAddress(\n        uint256 _meanValue,\n        address _seed,\n        uint256 _maxDeviation\n    ) private pure returns (uint256 value_) {\n        // Value between [0, 100]\n        uint256 senderRandomFactor = uint256(uint8(_seed))\n            .mul(100)\n            .div(256)\n            .mul(_maxDeviation)\n            .div(100);\n\n        value_ = __calcDeviatedValue(_meanValue, senderRandomFactor, _maxDeviation);\n\n        return value_;\n    }\n\n    /// @dev Calculates a a pseudo-randomized value as a seed an uint256\n    function __calcValueRandomizedByUint(\n        uint256 _meanValue,\n        uint256 _seed,\n        uint256 _maxDeviation\n    ) private pure returns (uint256 value_) {\n        // Depending on the _seed number, it will be one of {20, 40, 60, 80, 100}\n        uint256 randomFactor = (_seed.mod(2).mul(20))\n            .add((_seed.mod(3).mul(40)))\n            .mul(_maxDeviation)\n            .div(100);\n\n        value_ = __calcDeviatedValue(_meanValue, randomFactor, _maxDeviation);\n\n        return value_;\n    }\n\n    /// @dev Given a mean value and a max deviation, returns a value in the spectrum between 0 (_meanValue - maxDeviation) and 100 (_mean + maxDeviation)\n    /// TODO: Refactor to use 18 decimal precision\n    function __calcDeviatedValue(\n        uint256 _meanValue,\n        uint256 _offset,\n        uint256 _maxDeviation\n    ) private pure returns (uint256 value_) {\n        return\n            _meanValue.add((_meanValue.mul((uint256(2)).mul(_offset)).div(uint256(100)))).sub(\n                _meanValue.mul(_maxDeviation).div(uint256(100))\n            );\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function getMaxDeviationPerSender() public view returns (uint256 maxDeviationPerSender_) {\n        return maxDeviationPerSender;\n    }\n\n    function getValueInterpreter() public view returns (address valueInterpreter_) {\n        return valueInterpreter;\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\nimport \"../GSN/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 */\ncontract 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 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"
      },
      "contracts/mocks/integratees/MockUniswapV2Integratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../prices/CentralizedRateProvider.sol\";\nimport \"./utils/SimpleMockIntegrateeBase.sol\";\n\n/// @dev Mocks the integration with `UniswapV2Router02` <https://uniswap.org/docs/v2/smart-contracts/router02/>\n/// Additionally mocks the integration with `UniswapV2Factory` <https://uniswap.org/docs/v2/smart-contracts/factory/>\ncontract MockUniswapV2Integratee is SwapperBase, Ownable {\n    using SafeMath for uint256;\n    mapping(address => mapping(address => address)) private assetToAssetToPair;\n\n    address private immutable CENTRALIZED_RATE_PROVIDER;\n    uint256 private constant PRECISION = 18;\n\n    // Set in %, defines the MAX deviation per block from the mean rate\n    uint256 private blockNumberDeviation;\n\n    constructor(\n        address[] memory _listOfToken0,\n        address[] memory _listOfToken1,\n        address[] memory _listOfPair,\n        address _centralizedRateProvider,\n        uint256 _blockNumberDeviation\n    ) public {\n        addPair(_listOfToken0, _listOfToken1, _listOfPair);\n        CENTRALIZED_RATE_PROVIDER = _centralizedRateProvider;\n        blockNumberDeviation = _blockNumberDeviation;\n    }\n\n    /// @dev Adds the maximum possible value from {_amountADesired _amountBDesired}\n    /// Makes use of the value interpreter to perform those calculations\n    function addLiquidity(\n        address _tokenA,\n        address _tokenB,\n        uint256 _amountADesired,\n        uint256 _amountBDesired,\n        uint256,\n        uint256,\n        address,\n        uint256\n    )\n        external\n        returns (\n            uint256,\n            uint256,\n            uint256\n        )\n    {\n        __addLiquidity(_tokenA, _tokenB, _amountADesired, _amountBDesired);\n    }\n\n    /// @dev Removes the specified amount of liquidity\n    /// Returns 50% of the incoming liquidity value on each token.\n    function removeLiquidity(\n        address _tokenA,\n        address _tokenB,\n        uint256 _liquidity,\n        uint256,\n        uint256,\n        address,\n        uint256\n    ) public returns (uint256, uint256) {\n        __removeLiquidity(_tokenA, _tokenB, _liquidity);\n    }\n\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256,\n        address[] calldata path,\n        address,\n        uint256\n    ) external returns (uint256[] memory) {\n        uint256 amountOut = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomized(path[0], amountIn, path[1], blockNumberDeviation);\n\n        __swapAssets(msg.sender, path[0], amountIn, path[path.length - 1], amountOut);\n    }\n\n    /// @dev We don't calculate any intermediate values here because they aren't actually used\n    /// Returns the randomized by sender value of the edge path assets\n    function getAmountsOut(uint256 _amountIn, address[] calldata _path)\n        external\n        returns (uint256[] memory amounts_)\n    {\n        require(_path.length >= 2, \"getAmountsOut: path must be >= 2\");\n\n        address assetIn = _path[0];\n        address assetOut = _path[_path.length - 1];\n\n        uint256 amountOut = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomizedBySender(assetIn, _amountIn, assetOut);\n\n        amounts_ = new uint256[](_path.length);\n        amounts_[0] = _amountIn;\n        amounts_[_path.length - 1] = amountOut;\n\n        return amounts_;\n    }\n\n    function addPair(\n        address[] memory _listOfToken0,\n        address[] memory _listOfToken1,\n        address[] memory _listOfPair\n    ) public onlyOwner {\n        require(\n            _listOfPair.length == _listOfToken0.length,\n            \"constructor: _listOfPair and _listOfToken0 have an unequal length\"\n        );\n        require(\n            _listOfPair.length == _listOfToken1.length,\n            \"constructor: _listOfPair and _listOfToken1 have an unequal length\"\n        );\n        for (uint256 i; i < _listOfPair.length; i++) {\n            address token0 = _listOfToken0[i];\n            address token1 = _listOfToken1[i];\n            address pair = _listOfPair[i];\n            assetToAssetToPair[token0][token1] = pair;\n            assetToAssetToPair[token1][token0] = pair;\n        }\n    }\n\n    function setBlockNumberDeviation(uint256 _deviationPct) external onlyOwner {\n        blockNumberDeviation = _deviationPct;\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// Avoids stack-too-deep error.\n    function __addLiquidity(\n        address _tokenA,\n        address _tokenB,\n        uint256 _amountADesired,\n        uint256 _amountBDesired\n    ) private {\n        address pair = getPair(_tokenA, _tokenB);\n\n        uint256 amountA;\n        uint256 amountB;\n\n        uint256 amountBFromA = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(_tokenA, _amountADesired, _tokenB);\n        uint256 amountAFromB = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(_tokenB, _amountBDesired, _tokenA);\n\n        if (amountBFromA >= _amountBDesired) {\n            amountA = amountAFromB;\n            amountB = _amountBDesired;\n        } else {\n            amountA = _amountADesired;\n            amountB = amountBFromA;\n        }\n\n        uint256 tokenPerLPToken = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(pair, 10**uint256(PRECISION), _tokenA);\n\n        // Calculate the inverse rate to know the amount of LPToken to return from a unit of token\n        uint256 inverseRate = uint256(10**PRECISION).mul(10**PRECISION).div(tokenPerLPToken);\n\n        // Total liquidity can be calculated as 2x liquidity from amount A\n        uint256 totalLiquidity = uint256(2).mul(\n            amountA.mul(inverseRate).div(uint256(10**PRECISION))\n        );\n\n        require(\n            ERC20(pair).balanceOf(address(this)) >= totalLiquidity,\n            \"__addLiquidity: Integratee doesn't have enough pair balance to cover the expected amount\"\n        );\n\n        address[] memory assetsToIntegratee = new address[](2);\n        uint256[] memory assetsToIntegrateeAmounts = new uint256[](2);\n        address[] memory assetsFromIntegratee = new address[](1);\n        uint256[] memory assetsFromIntegrateeAmounts = new uint256[](1);\n\n        assetsToIntegratee[0] = _tokenA;\n        assetsToIntegrateeAmounts[0] = amountA;\n        assetsToIntegratee[1] = _tokenB;\n        assetsToIntegrateeAmounts[1] = amountB;\n        assetsFromIntegratee[0] = pair;\n        assetsFromIntegrateeAmounts[0] = totalLiquidity;\n\n        __swap(\n            msg.sender,\n            assetsToIntegratee,\n            assetsToIntegrateeAmounts,\n            assetsFromIntegratee,\n            assetsFromIntegrateeAmounts\n        );\n    }\n\n    /// Avoids stack-too-deep error.\n    function __removeLiquidity(\n        address _tokenA,\n        address _tokenB,\n        uint256 _liquidity\n    ) private {\n        address pair = assetToAssetToPair[_tokenA][_tokenB];\n        require(pair != address(0), \"__removeLiquidity: this pair doesn't exist\");\n\n        uint256 amountA = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(pair, _liquidity, _tokenA)\n            .div(uint256(2));\n\n        uint256 amountB = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(pair, _liquidity, _tokenB)\n            .div(uint256(2));\n\n        address[] memory assetsToIntegratee = new address[](1);\n        uint256[] memory assetsToIntegrateeAmounts = new uint256[](1);\n        address[] memory assetsFromIntegratee = new address[](2);\n        uint256[] memory assetsFromIntegrateeAmounts = new uint256[](2);\n\n        assetsToIntegratee[0] = pair;\n        assetsToIntegrateeAmounts[0] = _liquidity;\n        assetsFromIntegratee[0] = _tokenA;\n        assetsFromIntegrateeAmounts[0] = amountA;\n        assetsFromIntegratee[1] = _tokenB;\n        assetsFromIntegrateeAmounts[1] = amountB;\n\n        require(\n            ERC20(_tokenA).balanceOf(address(this)) >= amountA,\n            \"__removeLiquidity: Integratee doesn't have enough tokenA balance to cover the expected amount\"\n        );\n        require(\n            ERC20(_tokenB).balanceOf(address(this)) >= amountA,\n            \"__removeLiquidity: Integratee doesn't have enough tokenB balance to cover the expected amount\"\n        );\n\n        __swap(\n            msg.sender,\n            assetsToIntegratee,\n            assetsToIntegrateeAmounts,\n            assetsFromIntegratee,\n            assetsFromIntegrateeAmounts\n        );\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @dev By default set to address(0). It is read by UniswapV2PoolTokenValueCalculator: __calcPoolTokenValue\n    function feeTo() external pure returns (address) {\n        return address(0);\n    }\n\n    function getCentralizedRateProvider() public view returns (address) {\n        return CENTRALIZED_RATE_PROVIDER;\n    }\n\n    function getBlockNumberDeviation() public view returns (uint256) {\n        return blockNumberDeviation;\n    }\n\n    function getPrecision() public pure returns (uint256) {\n        return PRECISION;\n    }\n\n    function getPair(address _token0, address _token1) public view returns (address) {\n        return assetToAssetToPair[_token0][_token1];\n    }\n}\n"
      },
      "contracts/mocks/integratees/utils/SimpleMockIntegrateeBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./MockIntegrateeBase.sol\";\n\nabstract contract SimpleMockIntegrateeBase is MockIntegrateeBase {\n    constructor(\n        address[] memory _defaultRateAssets,\n        address[] memory _specialAssets,\n        uint8[] memory _specialAssetDecimals,\n        uint256 _ratePrecision\n    )\n        public\n        MockIntegrateeBase(\n            _defaultRateAssets,\n            _specialAssets,\n            _specialAssetDecimals,\n            _ratePrecision\n        )\n    {}\n\n    function __getRateAndSwapAssets(\n        address payable _trader,\n        address _srcToken,\n        uint256 _srcAmount,\n        address _destToken\n    ) internal returns (uint256 destAmount_) {\n        uint256 actualRate = __getRate(_srcToken, _destToken);\n        __swapAssets(_trader, _srcToken, _srcAmount, _destToken, actualRate);\n        return actualRate;\n    }\n}\n"
      },
      "contracts/mocks/integratees/utils/MockIntegrateeBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/NormalizedRateProviderBase.sol\";\nimport \"../../utils/SwapperBase.sol\";\n\nabstract contract MockIntegrateeBase is NormalizedRateProviderBase, SwapperBase {\n    constructor(\n        address[] memory _defaultRateAssets,\n        address[] memory _specialAssets,\n        uint8[] memory _specialAssetDecimals,\n        uint256 _ratePrecision\n    )\n        public\n        NormalizedRateProviderBase(\n            _defaultRateAssets,\n            _specialAssets,\n            _specialAssetDecimals,\n            _ratePrecision\n        )\n    {}\n\n    function __getRate(address _baseAsset, address _quoteAsset)\n        internal\n        view\n        override\n        returns (uint256)\n    {\n        // 1. Return constant if base asset is quote asset\n        if (_baseAsset == _quoteAsset) {\n            return 10**RATE_PRECISION;\n        }\n\n        // 2. Check for a direct rate\n        uint256 directRate = assetToAssetRate[_baseAsset][_quoteAsset];\n        if (directRate > 0) {\n            return directRate;\n        }\n\n        // 3. Check for inverse direct rate\n        uint256 iDirectRate = assetToAssetRate[_quoteAsset][_baseAsset];\n        if (iDirectRate > 0) {\n            return 10**(RATE_PRECISION.mul(2)).div(iDirectRate);\n        }\n\n        // 4. Else return 1\n        return 10**RATE_PRECISION;\n    }\n}\n"
      },
      "contracts/mocks/utils/NormalizedRateProviderBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"./RateProviderBase.sol\";\n\nabstract contract NormalizedRateProviderBase is RateProviderBase {\n    using SafeMath for uint256;\n\n    uint256 public immutable RATE_PRECISION;\n\n    constructor(\n        address[] memory _defaultRateAssets,\n        address[] memory _specialAssets,\n        uint8[] memory _specialAssetDecimals,\n        uint256 _ratePrecision\n    ) public RateProviderBase(_specialAssets, _specialAssetDecimals) {\n        RATE_PRECISION = _ratePrecision;\n\n        for (uint256 i = 0; i < _defaultRateAssets.length; i++) {\n            for (uint256 j = i + 1; j < _defaultRateAssets.length; j++) {\n                assetToAssetRate[_defaultRateAssets[i]][_defaultRateAssets[j]] =\n                    10**_ratePrecision;\n                assetToAssetRate[_defaultRateAssets[j]][_defaultRateAssets[i]] =\n                    10**_ratePrecision;\n            }\n        }\n    }\n\n    // TODO: move to main contracts' utils for use with prices\n    function __calcDenormalizedQuoteAssetAmount(\n        uint256 _baseAssetDecimals,\n        uint256 _baseAssetAmount,\n        uint256 _quoteAssetDecimals,\n        uint256 _rate\n    ) internal view returns (uint256) {\n        return\n            _rate.mul(_baseAssetAmount).mul(10**_quoteAssetDecimals).div(\n                10**(RATE_PRECISION.add(_baseAssetDecimals))\n            );\n    }\n}\n"
      },
      "contracts/mocks/utils/SwapperBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./EthConstantMixin.sol\";\n\nabstract contract SwapperBase is EthConstantMixin {\n    receive() external payable {}\n\n    function __swapAssets(\n        address payable _trader,\n        address _srcToken,\n        uint256 _srcAmount,\n        address _destToken,\n        uint256 _actualRate\n    ) internal returns (uint256 destAmount_) {\n        address[] memory assetsToIntegratee = new address[](1);\n        assetsToIntegratee[0] = _srcToken;\n        uint256[] memory assetsToIntegrateeAmounts = new uint256[](1);\n        assetsToIntegrateeAmounts[0] = _srcAmount;\n\n        address[] memory assetsFromIntegratee = new address[](1);\n        assetsFromIntegratee[0] = _destToken;\n        uint256[] memory assetsFromIntegrateeAmounts = new uint256[](1);\n        assetsFromIntegrateeAmounts[0] = _actualRate;\n        __swap(\n            _trader,\n            assetsToIntegratee,\n            assetsToIntegrateeAmounts,\n            assetsFromIntegratee,\n            assetsFromIntegrateeAmounts\n        );\n\n        return assetsFromIntegrateeAmounts[0];\n    }\n\n    function __swap(\n        address payable _trader,\n        address[] memory _assetsToIntegratee,\n        uint256[] memory _assetsToIntegrateeAmounts,\n        address[] memory _assetsFromIntegratee,\n        uint256[] memory _assetsFromIntegrateeAmounts\n    ) internal {\n        // Take custody of incoming assets\n        for (uint256 i = 0; i < _assetsToIntegratee.length; i++) {\n            address asset = _assetsToIntegratee[i];\n            uint256 amount = _assetsToIntegrateeAmounts[i];\n            require(asset != address(0), \"__swap: empty value in _assetsToIntegratee\");\n            require(amount > 0, \"__swap: empty value in _assetsToIntegrateeAmounts\");\n            // Incoming ETH amounts can be ignored\n            if (asset == ETH_ADDRESS) {\n                continue;\n            }\n            ERC20(asset).transferFrom(_trader, address(this), amount);\n        }\n\n        // Distribute outgoing assets\n        for (uint256 i = 0; i < _assetsFromIntegratee.length; i++) {\n            address asset = _assetsFromIntegratee[i];\n            uint256 amount = _assetsFromIntegrateeAmounts[i];\n            require(asset != address(0), \"__swap: empty value in _assetsFromIntegratee\");\n            require(amount > 0, \"__swap: empty value in _assetsFromIntegrateeAmounts\");\n            if (asset == ETH_ADDRESS) {\n                _trader.transfer(amount);\n            } else {\n                ERC20(asset).transfer(_trader, amount);\n            }\n        }\n    }\n}\n"
      },
      "contracts/mocks/utils/RateProviderBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./EthConstantMixin.sol\";\n\nabstract contract RateProviderBase is EthConstantMixin {\n    mapping(address => mapping(address => uint256)) public assetToAssetRate;\n\n    // Handles non-ERC20 compliant assets like ETH and USD\n    mapping(address => uint8) public specialAssetToDecimals;\n\n    constructor(address[] memory _specialAssets, uint8[] memory _specialAssetDecimals) public {\n        require(\n            _specialAssets.length == _specialAssetDecimals.length,\n            \"constructor: _specialAssets and _specialAssetDecimals are uneven lengths\"\n        );\n        for (uint256 i = 0; i < _specialAssets.length; i++) {\n            specialAssetToDecimals[_specialAssets[i]] = _specialAssetDecimals[i];\n        }\n\n        specialAssetToDecimals[ETH_ADDRESS] = 18;\n    }\n\n    function __getDecimalsForAsset(address _asset) internal view returns (uint256) {\n        uint256 decimals = specialAssetToDecimals[_asset];\n        if (decimals == 0) {\n            decimals = uint256(ERC20(_asset).decimals());\n        }\n\n        return decimals;\n    }\n\n    function __getRate(address _baseAsset, address _quoteAsset)\n        internal\n        view\n        virtual\n        returns (uint256)\n    {\n        return assetToAssetRate[_baseAsset][_quoteAsset];\n    }\n\n    function setRates(\n        address[] calldata _baseAssets,\n        address[] calldata _quoteAssets,\n        uint256[] calldata _rates\n    ) external {\n        require(\n            _baseAssets.length == _quoteAssets.length,\n            \"setRates: _baseAssets and _quoteAssets are uneven lengths\"\n        );\n        require(\n            _baseAssets.length == _rates.length,\n            \"setRates: _baseAssets and _rates are uneven lengths\"\n        );\n        for (uint256 i = 0; i < _baseAssets.length; i++) {\n            assetToAssetRate[_baseAssets[i]][_quoteAssets[i]] = _rates[i];\n        }\n    }\n}\n"
      },
      "contracts/mocks/utils/EthConstantMixin.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nabstract contract EthConstantMixin {\n    address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n}\n"
      },
      "contracts/mocks/integratees/MockParaSwapIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../release/interfaces/IParaSwapAugustusSwapper.sol\";\nimport \"../prices/CentralizedRateProvider.sol\";\nimport \"../utils/SwapperBase.sol\";\n\ncontract MockParaSwapIntegratee is SwapperBase {\n    using SafeMath for uint256;\n\n    address private immutable MOCK_CENTRALIZED_RATE_PROVIDER;\n\n    // Deviation set in % defines the MAX deviation per block from the mean rate\n    uint256 private blockNumberDeviation;\n\n    constructor(address _mockCentralizedRateProvider, uint256 _blockNumberDeviation) public {\n        MOCK_CENTRALIZED_RATE_PROVIDER = _mockCentralizedRateProvider;\n        blockNumberDeviation = _blockNumberDeviation;\n    }\n\n    /// @dev Must be `public` to avoid error\n    function multiSwap(\n        address _fromToken,\n        address _toToken,\n        uint256 _fromAmount,\n        uint256, // toAmount (min received amount)\n        uint256, // expectedAmount\n        IParaSwapAugustusSwapper.Path[] memory _paths,\n        uint256, // mintPrice\n        address, // beneficiary\n        uint256, // donationPercentage\n        string memory // referrer\n    ) public payable returns (uint256) {\n        return __multiSwap(_fromToken, _toToken, _fromAmount, _paths);\n    }\n\n    /// @dev Helper to parse the total amount of network fees (in ETH) for the multiSwap() call\n    function __calcTotalNetworkFees(IParaSwapAugustusSwapper.Path[] memory _paths)\n        private\n        pure\n        returns (uint256 totalNetworkFees_)\n    {\n        for (uint256 i; i < _paths.length; i++) {\n            totalNetworkFees_ = totalNetworkFees_.add(_paths[i].totalNetworkFee);\n        }\n\n        return totalNetworkFees_;\n    }\n\n    /// @dev Helper to avoid the stack-too-deep error\n    function __multiSwap(\n        address _fromToken,\n        address _toToken,\n        uint256 _fromAmount,\n        IParaSwapAugustusSwapper.Path[] memory _paths\n    ) private returns (uint256) {\n        address[] memory assetsFromIntegratee = new address[](1);\n        assetsFromIntegratee[0] = _toToken;\n\n        uint256[] memory assetsFromIntegrateeAmounts = new uint256[](1);\n        assetsFromIntegrateeAmounts[0] = CentralizedRateProvider(MOCK_CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomized(_fromToken, _fromAmount, _toToken, blockNumberDeviation);\n\n        uint256 totalNetworkFees = __calcTotalNetworkFees(_paths);\n        address[] memory assetsToIntegratee;\n        uint256[] memory assetsToIntegrateeAmounts;\n        if (totalNetworkFees > 0) {\n            assetsToIntegratee = new address[](2);\n            assetsToIntegratee[1] = ETH_ADDRESS;\n\n            assetsToIntegrateeAmounts = new uint256[](2);\n            assetsToIntegrateeAmounts[1] = totalNetworkFees;\n        } else {\n            assetsToIntegratee = new address[](1);\n            assetsToIntegrateeAmounts = new uint256[](1);\n        }\n        assetsToIntegratee[0] = _fromToken;\n        assetsToIntegrateeAmounts[0] = _fromAmount;\n\n        __swap(\n            msg.sender,\n            assetsToIntegratee,\n            assetsToIntegrateeAmounts,\n            assetsFromIntegratee,\n            assetsFromIntegrateeAmounts\n        );\n\n        return assetsFromIntegrateeAmounts[0];\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function getBlockNumberDeviation() external view returns (uint256 blockNumberDeviation_) {\n        return blockNumberDeviation;\n    }\n\n    function getCentralizedRateProvider()\n        external\n        view\n        returns (address centralizedRateProvider_)\n    {\n        return MOCK_CENTRALIZED_RATE_PROVIDER;\n    }\n}\n"
      },
      "contracts/release/interfaces/IParaSwapAugustusSwapper.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n/// @title ParaSwap IAugustusSwapper interface\ninterface IParaSwapAugustusSwapper {\n    struct Route {\n        address payable exchange;\n        address targetExchange;\n        uint256 percent;\n        bytes payload;\n        uint256 networkFee;\n    }\n\n    struct Path {\n        address to;\n        uint256 totalNetworkFee;\n        Route[] routes;\n    }\n\n    function multiSwap(\n        address,\n        address,\n        uint256,\n        uint256,\n        uint256,\n        Path[] calldata,\n        uint256,\n        address payable,\n        uint256,\n        string calldata\n    ) external payable returns (uint256);\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/ParaSwapAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/IParaSwapAugustusSwapper.sol\";\nimport \"../../../../interfaces/IWETH.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title ParaSwapAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for interacting with ParaSwap\ncontract ParaSwapAdapter is AdapterBase {\n    using SafeMath for uint256;\n\n    string private constant REFERRER = \"enzyme\";\n\n    address private immutable EXCHANGE;\n    address private immutable TOKEN_TRANSFER_PROXY;\n    address private immutable WETH_TOKEN;\n\n    constructor(\n        address _integrationManager,\n        address _exchange,\n        address _tokenTransferProxy,\n        address _wethToken\n    ) public AdapterBase(_integrationManager) {\n        EXCHANGE = _exchange;\n        TOKEN_TRANSFER_PROXY = _tokenTransferProxy;\n        WETH_TOKEN = _wethToken;\n    }\n\n    /// @dev Needed to receive ETH refund from sent network fees\n    receive() external payable {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ An identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"PARASWAP\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        require(_selector == TAKE_ORDER_SELECTOR, \"parseAssetsForMethod: _selector invalid\");\n\n        (\n            address incomingAsset,\n            uint256 minIncomingAssetAmount,\n            ,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount,\n            IParaSwapAugustusSwapper.Path[] memory paths\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        // Format incoming assets\n        incomingAssets_ = new address[](1);\n        incomingAssets_[0] = incomingAsset;\n        minIncomingAssetAmounts_ = new uint256[](1);\n        minIncomingAssetAmounts_[0] = minIncomingAssetAmount;\n\n        // Format outgoing assets depending on if there are network fees\n        uint256 totalNetworkFees = __calcTotalNetworkFees(paths);\n        if (totalNetworkFees > 0) {\n            // We are not performing special logic if the incomingAsset is the fee asset\n            if (outgoingAsset == WETH_TOKEN) {\n                spendAssets_ = new address[](1);\n                spendAssets_[0] = outgoingAsset;\n\n                spendAssetAmounts_ = new uint256[](1);\n                spendAssetAmounts_[0] = outgoingAssetAmount.add(totalNetworkFees);\n            } else {\n                spendAssets_ = new address[](2);\n                spendAssets_[0] = outgoingAsset;\n                spendAssets_[1] = WETH_TOKEN;\n\n                spendAssetAmounts_ = new uint256[](2);\n                spendAssetAmounts_[0] = outgoingAssetAmount;\n                spendAssetAmounts_[1] = totalNetworkFees;\n            }\n        } else {\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = outgoingAsset;\n\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = outgoingAssetAmount;\n        }\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Trades assets on ParaSwap\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function takeOrder(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        __takeOrder(_vaultProxy, _encodedCallArgs);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to parse the total amount of network fees (in ETH) for the multiSwap() call\n    function __calcTotalNetworkFees(IParaSwapAugustusSwapper.Path[] memory _paths)\n        private\n        pure\n        returns (uint256 totalNetworkFees_)\n    {\n        for (uint256 i; i < _paths.length; i++) {\n            totalNetworkFees_ = totalNetworkFees_.add(_paths[i].totalNetworkFee);\n        }\n\n        return totalNetworkFees_;\n    }\n\n    /// @dev Helper to decode the encoded callOnIntegration call arguments\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address incomingAsset_,\n            uint256 minIncomingAssetAmount_,\n            uint256 expectedIncomingAssetAmount_, // Passed as a courtesy to ParaSwap for analytics\n            address outgoingAsset_,\n            uint256 outgoingAssetAmount_,\n            IParaSwapAugustusSwapper.Path[] memory paths_\n        )\n    {\n        return\n            abi.decode(\n                _encodedCallArgs,\n                (address, uint256, uint256, address, uint256, IParaSwapAugustusSwapper.Path[])\n            );\n    }\n\n    /// @dev Helper to encode the call to ParaSwap multiSwap() as low-level calldata.\n    /// Avoids the stack-too-deep error.\n    function __encodeMultiSwapCallData(\n        address _vaultProxy,\n        address _incomingAsset,\n        uint256 _minIncomingAssetAmount,\n        uint256 _expectedIncomingAssetAmount, // Passed as a courtesy to ParaSwap for analytics\n        address _outgoingAsset,\n        uint256 _outgoingAssetAmount,\n        IParaSwapAugustusSwapper.Path[] memory _paths\n    ) private pure returns (bytes memory multiSwapCallData) {\n        return\n            abi.encodeWithSelector(\n                IParaSwapAugustusSwapper.multiSwap.selector,\n                _outgoingAsset, // fromToken\n                _incomingAsset, // toToken\n                _outgoingAssetAmount, // fromAmount\n                _minIncomingAssetAmount, // toAmount\n                _expectedIncomingAssetAmount, // expectedAmount\n                _paths, // path\n                0, // mintPrice\n                payable(_vaultProxy), // beneficiary\n                0, // donationPercentage\n                REFERRER // referrer\n            );\n    }\n\n    /// @dev Helper to execute ParaSwapAugustusSwapper.multiSwap() via a low-level call.\n    /// Avoids the stack-too-deep error.\n    function __executeMultiSwap(bytes memory _multiSwapCallData, uint256 _totalNetworkFees)\n        private\n    {\n        (bool success, bytes memory returnData) = EXCHANGE.call{value: _totalNetworkFees}(\n            _multiSwapCallData\n        );\n        require(success, string(returnData));\n    }\n\n    /// @dev Helper for the inner takeOrder() logic.\n    /// Avoids the stack-too-deep error.\n    function __takeOrder(address _vaultProxy, bytes memory _encodedCallArgs) private {\n        (\n            address incomingAsset,\n            uint256 minIncomingAssetAmount,\n            uint256 expectedIncomingAssetAmount,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount,\n            IParaSwapAugustusSwapper.Path[] memory paths\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        __approveMaxAsNeeded(outgoingAsset, TOKEN_TRANSFER_PROXY, outgoingAssetAmount);\n\n        // If there are network fees, unwrap enough WETH to cover the fees\n        uint256 totalNetworkFees = __calcTotalNetworkFees(paths);\n        if (totalNetworkFees > 0) {\n            __unwrapWeth(totalNetworkFees);\n        }\n\n        // Get the callData for the low-level multiSwap() call\n        bytes memory multiSwapCallData = __encodeMultiSwapCallData(\n            _vaultProxy,\n            incomingAsset,\n            minIncomingAssetAmount,\n            expectedIncomingAssetAmount,\n            outgoingAsset,\n            outgoingAssetAmount,\n            paths\n        );\n\n        // Execute the trade on ParaSwap\n        __executeMultiSwap(multiSwapCallData, totalNetworkFees);\n\n        // If fees were paid and ETH remains in the contract, wrap it as WETH so it can be returned\n        if (totalNetworkFees > 0) {\n            __wrapEth();\n        }\n    }\n\n    /// @dev Helper to unwrap specified amount of WETH into ETH.\n    /// Avoids the stack-too-deep error.\n    function __unwrapWeth(uint256 _amount) private {\n        IWETH(payable(WETH_TOKEN)).withdraw(_amount);\n    }\n\n    /// @dev Helper to wrap all ETH in contract as WETH.\n    /// Avoids the stack-too-deep error.\n    function __wrapEth() private {\n        uint256 ethBalance = payable(address(this)).balance;\n        if (ethBalance > 0) {\n            IWETH(payable(WETH_TOKEN)).deposit{value: ethBalance}();\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `EXCHANGE` variable\n    /// @return exchange_ The `EXCHANGE` variable value\n    function getExchange() external view returns (address exchange_) {\n        return EXCHANGE;\n    }\n\n    /// @notice Gets the `TOKEN_TRANSFER_PROXY` variable\n    /// @return tokenTransferProxy_ The `TOKEN_TRANSFER_PROXY` variable value\n    function getTokenTransferProxy() external view returns (address tokenTransferProxy_) {\n        return TOKEN_TRANSFER_PROXY;\n    }\n\n    /// @notice Gets the `WETH_TOKEN` variable\n    /// @return wethToken_ The `WETH_TOKEN` variable value\n    function getWethToken() external view returns (address wethToken_) {\n        return WETH_TOKEN;\n    }\n}\n"
      },
      "contracts/release/interfaces/IWETH.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title WETH Interface\n/// @author Enzyme Council <security@enzyme.finance>\ninterface IWETH {\n    function deposit() external payable;\n\n    function withdraw(uint256) external;\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/KyberAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"../../../../interfaces/IKyberNetworkProxy.sol\";\nimport \"../../../../interfaces/IWETH.sol\";\nimport \"../../../../utils/MathHelpers.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title KyberAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for interacting with Kyber Network\ncontract KyberAdapter is AdapterBase, MathHelpers {\n    address private immutable EXCHANGE;\n    address private immutable WETH_TOKEN;\n\n    constructor(\n        address _integrationManager,\n        address _exchange,\n        address _wethToken\n    ) public AdapterBase(_integrationManager) {\n        EXCHANGE = _exchange;\n        WETH_TOKEN = _wethToken;\n    }\n\n    /// @dev Needed to receive ETH from swap\n    receive() external payable {}\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ An identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"KYBER_NETWORK\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        require(_selector == TAKE_ORDER_SELECTOR, \"parseAssetsForMethod: _selector invalid\");\n\n        (\n            address incomingAsset,\n            uint256 minIncomingAssetAmount,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        require(\n            incomingAsset != outgoingAsset,\n            \"parseAssetsForMethod: incomingAsset and outgoingAsset asset cannot be the same\"\n        );\n        require(outgoingAssetAmount > 0, \"parseAssetsForMethod: outgoingAssetAmount must be >0\");\n\n        spendAssets_ = new address[](1);\n        spendAssets_[0] = outgoingAsset;\n        spendAssetAmounts_ = new uint256[](1);\n        spendAssetAmounts_[0] = outgoingAssetAmount;\n\n        incomingAssets_ = new address[](1);\n        incomingAssets_[0] = incomingAsset;\n        minIncomingAssetAmounts_ = new uint256[](1);\n        minIncomingAssetAmounts_[0] = minIncomingAssetAmount;\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Trades assets on Kyber\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function takeOrder(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (\n            address incomingAsset,\n            uint256 minIncomingAssetAmount,\n            address outgoingAsset,\n            uint256 outgoingAssetAmount\n        ) = __decodeCallArgs(_encodedCallArgs);\n\n        uint256 minExpectedRate = __calcNormalizedRate(\n            ERC20(outgoingAsset).decimals(),\n            outgoingAssetAmount,\n            ERC20(incomingAsset).decimals(),\n            minIncomingAssetAmount\n        );\n\n        if (outgoingAsset == WETH_TOKEN) {\n            __swapNativeAssetToToken(incomingAsset, outgoingAssetAmount, minExpectedRate);\n        } else if (incomingAsset == WETH_TOKEN) {\n            __swapTokenToNativeAsset(outgoingAsset, outgoingAssetAmount, minExpectedRate);\n        } else {\n            __swapTokenToToken(incomingAsset, outgoingAsset, outgoingAssetAmount, minExpectedRate);\n        }\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode the encoded call arguments\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address incomingAsset_,\n            uint256 minIncomingAssetAmount_,\n            address outgoingAsset_,\n            uint256 outgoingAssetAmount_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (address, uint256, address, uint256));\n    }\n\n    /// @dev Executes a swap of ETH to ERC20\n    function __swapNativeAssetToToken(\n        address _incomingAsset,\n        uint256 _outgoingAssetAmount,\n        uint256 _minExpectedRate\n    ) private {\n        IWETH(payable(WETH_TOKEN)).withdraw(_outgoingAssetAmount);\n\n        IKyberNetworkProxy(EXCHANGE).swapEtherToToken{value: _outgoingAssetAmount}(\n            _incomingAsset,\n            _minExpectedRate\n        );\n    }\n\n    /// @dev Executes a swap of ERC20 to ETH\n    function __swapTokenToNativeAsset(\n        address _outgoingAsset,\n        uint256 _outgoingAssetAmount,\n        uint256 _minExpectedRate\n    ) private {\n        __approveMaxAsNeeded(_outgoingAsset, EXCHANGE, _outgoingAssetAmount);\n\n        IKyberNetworkProxy(EXCHANGE).swapTokenToEther(\n            _outgoingAsset,\n            _outgoingAssetAmount,\n            _minExpectedRate\n        );\n\n        IWETH(payable(WETH_TOKEN)).deposit{value: payable(address(this)).balance}();\n    }\n\n    /// @dev Executes a swap of ERC20 to ERC20\n    function __swapTokenToToken(\n        address _incomingAsset,\n        address _outgoingAsset,\n        uint256 _outgoingAssetAmount,\n        uint256 _minExpectedRate\n    ) private {\n        __approveMaxAsNeeded(_outgoingAsset, EXCHANGE, _outgoingAssetAmount);\n\n        IKyberNetworkProxy(EXCHANGE).swapTokenToToken(\n            _outgoingAsset,\n            _outgoingAssetAmount,\n            _incomingAsset,\n            _minExpectedRate\n        );\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `EXCHANGE` variable\n    /// @return exchange_ The `EXCHANGE` variable value\n    function getExchange() external view returns (address exchange_) {\n        return EXCHANGE;\n    }\n\n    /// @notice Gets the `WETH_TOKEN` variable\n    /// @return wethToken_ The `WETH_TOKEN` variable value\n    function getWethToken() external view returns (address wethToken_) {\n        return WETH_TOKEN;\n    }\n}\n"
      },
      "contracts/release/interfaces/IKyberNetworkProxy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title Kyber Network interface\ninterface IKyberNetworkProxy {\n    function swapEtherToToken(address, uint256) external payable returns (uint256);\n\n    function swapTokenToEther(\n        address,\n        uint256,\n        uint256\n    ) external returns (uint256);\n\n    function swapTokenToToken(\n        address,\n        uint256,\n        address,\n        uint256\n    ) external returns (uint256);\n}\n"
      },
      "contracts/mocks/prices/MockUniswapV2PriceSource.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../release/interfaces/IUniswapV2Pair.sol\";\nimport \"../tokens/MockToken.sol\";\n\n/// @dev This price source mocks the integration with Uniswap Pair\n/// Docs of Uniswap Pair implementation: <https://uniswap.org/docs/v2/smart-contracts/pair/>\ncontract MockUniswapV2PriceSource is MockToken(\"Uniswap V2\", \"UNI-V2\", 18) {\n    address private immutable TOKEN_0;\n    address private immutable TOKEN_1;\n\n    constructor(address _token0, address _token1) public {\n        TOKEN_0 = _token0;\n        TOKEN_1 = _token1;\n    }\n\n    /// @dev returns reserves for each token on the Uniswap Pair\n    /// Reserves will be used to calculate the pair price\n    /// Inherited from IUniswapV2Pair\n    function getReserves()\n        external\n        view\n        returns (\n            uint112 reserve0,\n            uint112 reserve1,\n            uint32 blockTimestampLast\n        )\n    {\n        reserve0 = uint112(ERC20(token0()).balanceOf(address(this)));\n        reserve1 = uint112(ERC20(token1()).balanceOf(address(this)));\n        return (reserve0, reserve1, uint32(block.timestamp));\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @dev Inherited from IUniswapV2Pair\n    function token0() public view returns (address) {\n        return TOKEN_0;\n    }\n\n    /// @dev Inherited from IUniswapV2Pair\n    function token1() public view returns (address) {\n        return TOKEN_1;\n    }\n\n    /// @dev Inherited from IUniswapV2Pair\n    function kLast() public pure returns (uint256) {\n        return 0;\n    }\n}\n"
      },
      "contracts/mocks/tokens/MockToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\ncontract MockToken is ERC20Burnable {\n    using SafeMath for uint256;\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) public ERC20(_name, _symbol) {\n        _setupDecimals(_decimals);\n        _mint(msg.sender, uint256(100000000).mul(10**uint256(_decimals)));\n    }\n\n    function mintFor(address _who, uint256 _amount) external {\n        _mint(_who, _amount);\n    }\n\n    function mint(uint256 _amount) external {\n        _mint(msg.sender, _amount);\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./ERC20.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\nabstract contract ERC20Burnable is Context, ERC20 {\n    /**\n     * @dev Destroys `amount` tokens from the caller.\n     *\n     * See {ERC20-_burn}.\n     */\n    function burn(uint256 amount) public virtual {\n        _burn(_msgSender(), amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, deducting from the caller's\n     * allowance.\n     *\n     * See {ERC20-_burn} and {ERC20-allowance}.\n     *\n     * Requirements:\n     *\n     * - the caller must have allowance for ``accounts``'s tokens of at least\n     * `amount`.\n     */\n    function burnFrom(address account, uint256 amount) public virtual {\n        uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, \"ERC20: burn amount exceeds allowance\");\n\n        _approve(account, _msgSender(), decreasedAllowance);\n        _burn(account, amount);\n    }\n}\n"
      },
      "contracts/mocks/tokens/MockReentrancyToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../release/core/fund/comptroller/ComptrollerLib.sol\";\nimport \"./MockToken.sol\";\n\n/// @title MockReentrancyToken Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mock ERC20 token implementation that is able to re-entrance redeemShares and buyShares functions\ncontract MockReentrancyToken is MockToken(\"Mock Reentrancy Token\", \"MRT\", 18) {\n    bool public bad;\n    address public comptrollerProxy;\n\n    function makeItReentracyToken(address _comptrollerProxy) external {\n        bad = true;\n        comptrollerProxy = _comptrollerProxy;\n    }\n\n    function transfer(address recipient, uint256 amount) public override returns (bool) {\n        if (bad) {\n            ComptrollerLib(comptrollerProxy).redeemShares();\n        } else {\n            _transfer(_msgSender(), recipient, amount);\n        }\n        return true;\n    }\n\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) public override returns (bool) {\n        if (bad) {\n            ComptrollerLib(comptrollerProxy).buyShares(\n                new address[](0),\n                new uint256[](0),\n                new uint256[](0)\n            );\n        } else {\n            _transfer(sender, recipient, amount);\n        }\n        return true;\n    }\n}\n"
      },
      "contracts/mocks/tokens/MockSynthetixToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"./../../release/interfaces/ISynthetixProxyERC20.sol\";\nimport \"./../../release/interfaces/ISynthetixSynth.sol\";\nimport \"./MockToken.sol\";\n\ncontract MockSynthetixToken is ISynthetixProxyERC20, ISynthetixSynth, MockToken, Ownable {\n    using SafeMath for uint256;\n\n    bytes32 public override currencyKey;\n    uint256 public constant WAITING_PERIOD_SECS = 3 * 60;\n\n    mapping(address => uint256) public timelockByAccount;\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals,\n        bytes32 _currencyKey\n    ) public MockToken(_name, _symbol, _decimals) {\n        currencyKey = _currencyKey;\n    }\n\n    function setCurrencyKey(bytes32 _currencyKey) external onlyOwner {\n        currencyKey = _currencyKey;\n    }\n\n    function _isLocked(address account) internal view returns (bool) {\n        return timelockByAccount[account] >= now;\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address,\n        uint256\n    ) internal override {\n        require(!_isLocked(from), \"Cannot settle during waiting period\");\n    }\n\n    function target() external view override returns (address) {\n        return address(this);\n    }\n\n    function isLocked(address account) external view returns (bool) {\n        return _isLocked(account);\n    }\n\n    function burnFrom(address account, uint256 amount) public override {\n        _burn(account, amount);\n    }\n\n    function lock(address account) public {\n        timelockByAccount[account] = now.add(WAITING_PERIOD_SECS);\n    }\n\n    function unlock(address account) public {\n        timelockByAccount[account] = 0;\n    }\n}\n"
      },
      "contracts/mocks/prices/MockSynthetixPriceSource.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"./../../release/interfaces/ISynthetixExchangeRates.sol\";\nimport \"../prices/MockChainlinkPriceSource.sol\";\n\n/// @dev This price source offers two different options getting prices\n/// The first one is getting a fixed rate, which can be useful for tests\n/// The second approach calculates dinamically the rate making use of a chainlink price source\n/// Mocks the functionality of the folllowing Synthetix contracts: { Exchanger, ExchangeRates }\ncontract MockSynthetixPriceSource is Ownable, ISynthetixExchangeRates {\n    using SafeMath for uint256;\n\n    mapping(bytes32 => uint256) private fixedRate;\n    mapping(bytes32 => AggregatorInfo) private currencyKeyToAggregator;\n\n    enum RateAsset {ETH, USD}\n\n    struct AggregatorInfo {\n        address aggregator;\n        RateAsset rateAsset;\n    }\n\n    constructor(address _ethUsdAggregator) public {\n        currencyKeyToAggregator[bytes32(\"ETH\")] = AggregatorInfo({\n            aggregator: _ethUsdAggregator,\n            rateAsset: RateAsset.USD\n        });\n    }\n\n    function setPriceSourcesForCurrencyKeys(\n        bytes32[] calldata _currencyKeys,\n        address[] calldata _aggregators,\n        RateAsset[] calldata _rateAssets\n    ) external onlyOwner {\n        require(\n            _currencyKeys.length == _aggregators.length &&\n                _rateAssets.length == _aggregators.length\n        );\n        for (uint256 i = 0; i < _currencyKeys.length; i++) {\n            currencyKeyToAggregator[_currencyKeys[i]] = AggregatorInfo({\n                aggregator: _aggregators[i],\n                rateAsset: _rateAssets[i]\n            });\n        }\n    }\n\n    function setRate(bytes32 _currencyKey, uint256 _rate) external onlyOwner {\n        fixedRate[_currencyKey] = _rate;\n    }\n\n    /// @dev Calculates the rate from a currencty key against its RateAsset\n    /// TODO: Use CentralizedRateProvider to randomize and make consistent with the rest\n    function rateAndInvalid(bytes32 _currencyKey)\n        external\n        view\n        override\n        returns (uint256 rate_, bool isInvalid_)\n    {\n        uint256 storedRate = getFixedRate(_currencyKey);\n        if (storedRate != 0) {\n            rate_ = storedRate;\n        } else {\n            AggregatorInfo memory aggregatorInfo = getAggregatorFromCurrencyKey(_currencyKey);\n            address aggregator = aggregatorInfo.aggregator;\n\n            if (aggregator != address(0)) {\n                uint256 decimals = MockChainlinkPriceSource(aggregator).decimals();\n                rate_ = uint256(MockChainlinkPriceSource(aggregator).latestAnswer()).mul(\n                    10**(uint256(18).sub(decimals))\n                );\n\n                if (aggregatorInfo.rateAsset == RateAsset.ETH) {\n                    uint256 ethToUsd = uint256(\n                        MockChainlinkPriceSource(\n                            getAggregatorFromCurrencyKey(bytes32(\"ETH\"))\n                                .aggregator\n                        )\n                            .latestAnswer()\n                    );\n                    rate_ = rate_.mul(ethToUsd).div(10**8);\n                }\n            }\n        }\n\n        isInvalid_ = (rate_ == 0);\n        return (rate_, isInvalid_);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function getAggregatorFromCurrencyKey(bytes32 _currencyKey)\n        public\n        view\n        returns (AggregatorInfo memory _aggregator)\n    {\n        return currencyKeyToAggregator[_currencyKey];\n    }\n\n    function getFixedRate(bytes32 _currencyKey) public view returns (uint256) {\n        return fixedRate[_currencyKey];\n    }\n}\n"
      },
      "contracts/mocks/prices/MockChainlinkPriceSource.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\ncontract MockChainlinkPriceSource {\n    event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);\n\n    uint256 public DECIMALS;\n\n    int256 public latestAnswer;\n    uint256 public latestTimestamp;\n    uint256 public roundId;\n    address public aggregator;\n\n    constructor(uint256 _decimals) public {\n        DECIMALS = _decimals;\n        latestAnswer = int256(10**_decimals);\n        latestTimestamp = now;\n        roundId = 1;\n        aggregator = address(this);\n    }\n\n    function setLatestAnswer(int256 _nextAnswer, uint256 _nextTimestamp) external {\n        latestAnswer = _nextAnswer;\n        latestTimestamp = _nextTimestamp;\n        roundId = roundId + 1;\n\n        emit AnswerUpdated(latestAnswer, roundId, latestTimestamp);\n    }\n\n    function setAggregator(address _nextAggregator) external {\n        aggregator = _nextAggregator;\n    }\n\n    function decimals() public view returns (uint256) {\n        return DECIMALS;\n    }\n}\n"
      },
      "contracts/mocks/integratees/MockSynthetixIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./../../release/interfaces/ISynthetixExchangeRates.sol\";\nimport \"./../tokens/MockSynthetixToken.sol\";\n\n/// @dev Synthetix Integratee. Mocks functionalities from the folllowing synthetix contracts\n/// Synthetix, SynthetixAddressResolver, SynthetixDelegateApprovals\n/// Link to contracts: <https://github.com/Synthetixio/synthetix/tree/develop/contracts>\ncontract MockSynthetixIntegratee is Ownable {\n    using SafeMath for uint256;\n\n    mapping(address => mapping(address => bool)) private authorizerToDelegateToApproval;\n    mapping(bytes32 => address) private currencyKeyToSynth;\n\n    address private immutable EXCHANGE_RATES;\n    uint256 private immutable FEE;\n\n    uint256 private constant UNIT_FEE = 1000;\n\n    constructor(uint256 _fee, address _exchangeRates) public {\n        FEE = _fee;\n        EXCHANGE_RATES = address(_exchangeRates);\n    }\n\n    receive() external payable {}\n\n    function exchangeOnBehalfWithTracking(\n        address _exchangeForAddress,\n        bytes32 _srcCurrencyKey,\n        uint256 _srcAmount,\n        bytes32 _destinationCurrencyKey,\n        address,\n        bytes32\n    ) external returns (uint256 amountReceived_) {\n        require(\n            canExchangeFor(msg.sender, _exchangeForAddress),\n            \"exchangeOnBehalfWithTracking: Not approved to act on behalf\"\n        );\n\n        amountReceived_ = __calculateAndSwap(\n            _exchangeForAddress,\n            _srcAmount,\n            _srcCurrencyKey,\n            _destinationCurrencyKey\n        );\n\n        return amountReceived_;\n    }\n\n    function getAmountsForExchange(\n        uint256 _srcAmount,\n        bytes32 _srcCurrencyKey,\n        bytes32 _destCurrencyKey\n    )\n        public\n        view\n        returns (\n            uint256 amountReceived_,\n            uint256 fee_,\n            uint256 exchangeFeeRate_\n        )\n    {\n        ISynthetixExchangeRates exchangeRates = ISynthetixExchangeRates(EXCHANGE_RATES);\n        require(\n            currencyKeyToSynth[_srcCurrencyKey] != address(0) &&\n                currencyKeyToSynth[_destCurrencyKey] != address(0),\n            \"getAmountsForExchange: Currency key doesn't have an associated synth\"\n        );\n\n        (uint256 srcRate, ) = exchangeRates.rateAndInvalid(_srcCurrencyKey);\n        (uint256 destRate, ) = exchangeRates.rateAndInvalid(_destCurrencyKey);\n        uint256 destAmount = _srcAmount.mul(srcRate).div(destRate);\n\n        exchangeFeeRate_ = FEE;\n        amountReceived_ = destAmount.mul(UNIT_FEE.sub(exchangeFeeRate_)).div(UNIT_FEE);\n        fee_ = destAmount.sub(amountReceived_);\n\n        return (amountReceived_, fee_, exchangeFeeRate_);\n    }\n\n    function setSynthFromCurrencyKeys(bytes32[] calldata _currencyKeys, address[] calldata _synths)\n        external\n        onlyOwner\n    {\n        require(\n            _currencyKeys.length == _synths.length,\n            \"setSynthFromCurrencyKey: Unequal _currencyKeys and _synths lengths\"\n        );\n        for (uint256 i = 0; i < _currencyKeys.length; i++) {\n            currencyKeyToSynth[_currencyKeys[i]] = _synths[i];\n        }\n    }\n\n    function approveExchangeOnBehalf(address _delegate) external {\n        authorizerToDelegateToApproval[msg.sender][_delegate] = true;\n    }\n\n    function __calculateAndSwap(\n        address _exchangeForAddress,\n        uint256 _srcAmount,\n        bytes32 _srcCurrencyKey,\n        bytes32 _destCurrencyKey\n    ) private returns (uint256 amountReceived_) {\n        MockSynthetixToken srcSynth = MockSynthetixToken(currencyKeyToSynth[_srcCurrencyKey]);\n        MockSynthetixToken destSynth = MockSynthetixToken(currencyKeyToSynth[_destCurrencyKey]);\n\n        require(address(srcSynth) != address(0), \"__calculateAndSwap: Source synth is not listed\");\n        require(\n            address(destSynth) != address(0),\n            \"__calculateAndSwap: Destination synth is not listed\"\n        );\n        require(\n            !srcSynth.isLocked(_exchangeForAddress),\n            \"__calculateAndSwap: Cannot settle during waiting period\"\n        );\n\n        (amountReceived_, , ) = getAmountsForExchange(\n            _srcAmount,\n            _srcCurrencyKey,\n            _destCurrencyKey\n        );\n\n        srcSynth.burnFrom(_exchangeForAddress, _srcAmount);\n        destSynth.mintFor(_exchangeForAddress, amountReceived_);\n        destSynth.lock(_exchangeForAddress);\n\n        return amountReceived_;\n    }\n\n    function requireAndGetAddress(bytes32 _name, string calldata)\n        external\n        view\n        returns (address resolvedAddress_)\n    {\n        if (_name == \"ExchangeRates\") {\n            return EXCHANGE_RATES;\n        }\n        return address(this);\n    }\n\n    function settle(address, bytes32)\n        external\n        returns (\n            uint256,\n            uint256,\n            uint256\n        )\n    {\n        // TODO\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function canExchangeFor(address, address) public pure returns (bool canExchange_) {\n        return true;\n    }\n\n    function getExchangeRates() public view returns (address exchangeRates_) {\n        return EXCHANGE_RATES;\n    }\n\n    function getFee() public view returns (uint256 fee_) {\n        return FEE;\n    }\n\n    function getSynthFromCurrencyKey(bytes32 _currencyKey) public view returns (address synth_) {\n        return currencyKeyToSynth[_currencyKey];\n    }\n\n    function getUnitFee() public pure returns (uint256 fee_) {\n        return UNIT_FEE;\n    }\n}\n"
      },
      "contracts/mocks/integratees/MockKyberIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../release/utils/MathHelpers.sol\";\nimport \"../prices/CentralizedRateProvider.sol\";\nimport \"../utils/SwapperBase.sol\";\n\ncontract MockKyberIntegratee is SwapperBase, Ownable, MathHelpers {\n    using SafeMath for uint256;\n\n    address private immutable MOCK_CENTRALIZED_RATE_PROVIDER;\n    address private immutable WETH;\n\n    uint256 private constant PRECISION = 18;\n\n    // Deviation set in % defines the MAX deviation per block from the mean rate\n    uint256 private blockNumberDeviation;\n\n    constructor(\n        address _mockCentralizedRateProvider,\n        address _weth,\n        uint256 _blockNumberDeviation\n    ) public {\n        MOCK_CENTRALIZED_RATE_PROVIDER = _mockCentralizedRateProvider;\n        WETH = _weth;\n        blockNumberDeviation = _blockNumberDeviation;\n    }\n\n    function swapEtherToToken(address _destToken, uint256) external payable returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(MOCK_CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomized(WETH, msg.value, _destToken, blockNumberDeviation);\n\n        __swapAssets(msg.sender, ETH_ADDRESS, msg.value, _destToken, destAmount);\n        return msg.value;\n    }\n\n    function swapTokenToEther(\n        address _srcToken,\n        uint256 _srcAmount,\n        uint256\n    ) external returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(MOCK_CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomized(_srcToken, _srcAmount, WETH, blockNumberDeviation);\n\n        __swapAssets(msg.sender, _srcToken, _srcAmount, ETH_ADDRESS, destAmount);\n        return _srcAmount;\n    }\n\n    function swapTokenToToken(\n        address _srcToken,\n        uint256 _srcAmount,\n        address _destToken,\n        uint256\n    ) external returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(MOCK_CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomized(_srcToken, _srcAmount, _destToken, blockNumberDeviation);\n\n        __swapAssets(msg.sender, _srcToken, _srcAmount, _destToken, destAmount);\n        return _srcAmount;\n    }\n\n    function setBlockNumberDeviation(uint256 _deviationPct) external onlyOwner {\n        blockNumberDeviation = _deviationPct;\n    }\n\n    function getExpectedRate(\n        address _srcToken,\n        address _destToken,\n        uint256 _amount\n    ) external returns (uint256 rate_, uint256 worstRate_) {\n        if (_srcToken == ETH_ADDRESS) {\n            _srcToken = WETH;\n        }\n        if (_destToken == ETH_ADDRESS) {\n            _destToken = WETH;\n        }\n\n        uint256 destAmount = CentralizedRateProvider(MOCK_CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValueRandomizedBySender(_srcToken, _amount, _destToken);\n        rate_ = __calcNormalizedRate(\n            ERC20(_srcToken).decimals(),\n            _amount,\n            ERC20(_destToken).decimals(),\n            destAmount\n        );\n        worstRate_ = rate_.mul(uint256(100).sub(blockNumberDeviation)).div(100);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function getCentralizedRateProvider() public view returns (address) {\n        return MOCK_CENTRALIZED_RATE_PROVIDER;\n    }\n\n    function getWeth() public view returns (address) {\n        return WETH;\n    }\n\n    function getBlockNumberDeviation() public view returns (uint256) {\n        return blockNumberDeviation;\n    }\n\n    function getPrecision() public pure returns (uint256) {\n        return PRECISION;\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/AssetWhitelist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../../../../core/fund/vault/VaultLib.sol\";\nimport \"../../../../utils/AddressArrayLib.sol\";\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/PostCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title AssetWhitelist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that only allows a configurable whitelist of assets in a fund's holdings\ncontract AssetWhitelist is PostCallOnIntegrationValidatePolicyBase, AddressListPolicyMixin {\n    using AddressArrayLib for address[];\n\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Validates and initializes a policy as necessary prior to fund activation\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _vaultProxy The fund's VaultProxy address\n    function activateForFund(address _comptrollerProxy, address _vaultProxy)\n        external\n        override\n        onlyPolicyManager\n    {\n        require(\n            passesRule(_comptrollerProxy, VaultLib(_vaultProxy).getTrackedAssets()),\n            \"activateForFund: Non-whitelisted asset detected\"\n        );\n    }\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        address[] memory assets = abi.decode(_encodedSettings, (address[]));\n        require(\n            assets.contains(ComptrollerLib(_comptrollerProxy).getDenominationAsset()),\n            \"addFundSettings: Must whitelist denominationAsset\"\n        );\n\n        __addToList(_comptrollerProxy, abi.decode(_encodedSettings, (address[])));\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ASSET_WHITELIST\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _assets The assets with which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address[] memory _assets)\n        public\n        view\n        returns (bool isValid_)\n    {\n        for (uint256 i; i < _assets.length; i++) {\n            if (!isInList(_comptrollerProxy, _assets[i])) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (, , address[] memory incomingAssets, , , ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, incomingAssets);\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/utils/AddressListPolicyMixin.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/utils/EnumerableSet.sol\";\n\n/// @title AddressListPolicyMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice An abstract mixin contract for policies that use an address list\nabstract contract AddressListPolicyMixin {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    event AddressesAdded(address indexed comptrollerProxy, address[] items);\n\n    event AddressesRemoved(address indexed comptrollerProxy, address[] items);\n\n    mapping(address => EnumerableSet.AddressSet) private comptrollerProxyToList;\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Get all addresses in a fund's list\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @return list_ The addresses in the fund's list\n    function getList(address _comptrollerProxy) external view returns (address[] memory list_) {\n        list_ = new address[](comptrollerProxyToList[_comptrollerProxy].length());\n        for (uint256 i = 0; i < list_.length; i++) {\n            list_[i] = comptrollerProxyToList[_comptrollerProxy].at(i);\n        }\n        return list_;\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Check if an address is in a fund's list\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _item The address to check against the list\n    /// @return isInList_ True if the address is in the list\n    function isInList(address _comptrollerProxy, address _item)\n        public\n        view\n        returns (bool isInList_)\n    {\n        return comptrollerProxyToList[_comptrollerProxy].contains(_item);\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Helper to add addresses to the calling fund's list\n    function __addToList(address _comptrollerProxy, address[] memory _items) internal {\n        require(_items.length > 0, \"__addToList: No addresses provided\");\n\n        for (uint256 i = 0; i < _items.length; i++) {\n            require(\n                comptrollerProxyToList[_comptrollerProxy].add(_items[i]),\n                \"__addToList: Address already exists in list\"\n            );\n        }\n\n        emit AddressesAdded(_comptrollerProxy, _items);\n    }\n\n    /// @dev Helper to remove addresses from the calling fund's list\n    function __removeFromList(address _comptrollerProxy, address[] memory _items) internal {\n        require(_items.length > 0, \"__removeFromList: No addresses provided\");\n\n        for (uint256 i = 0; i < _items.length; i++) {\n            require(\n                comptrollerProxyToList[_comptrollerProxy].remove(_items[i]),\n                \"__removeFromList: Address does not exist in list\"\n            );\n        }\n\n        emit AddressesRemoved(_comptrollerProxy, _items);\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/AssetBlacklist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../core/fund/comptroller/ComptrollerLib.sol\";\nimport \"../../../../core/fund/vault/VaultLib.sol\";\nimport \"../../../../utils/AddressArrayLib.sol\";\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/PostCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title AssetBlacklist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that disallows a configurable blacklist of assets in a fund's holdings\ncontract AssetBlacklist is PostCallOnIntegrationValidatePolicyBase, AddressListPolicyMixin {\n    using AddressArrayLib for address[];\n\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Validates and initializes a policy as necessary prior to fund activation\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _vaultProxy The fund's VaultProxy address\n    function activateForFund(address _comptrollerProxy, address _vaultProxy)\n        external\n        override\n        onlyPolicyManager\n    {\n        require(\n            passesRule(_comptrollerProxy, VaultLib(_vaultProxy).getTrackedAssets()),\n            \"activateForFund: Blacklisted asset detected\"\n        );\n    }\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        address[] memory assets = abi.decode(_encodedSettings, (address[]));\n        require(\n            !assets.contains(ComptrollerLib(_comptrollerProxy).getDenominationAsset()),\n            \"addFundSettings: Cannot blacklist denominationAsset\"\n        );\n\n        __addToList(_comptrollerProxy, assets);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ASSET_BLACKLIST\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _assets The assets with which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address[] memory _assets)\n        public\n        view\n        returns (bool isValid_)\n    {\n        for (uint256 i; i < _assets.length; i++) {\n            if (isInList(_comptrollerProxy, _assets[i])) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (, , address[] memory incomingAssets, , , ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, incomingAssets);\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/AdapterWhitelist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/PreCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title AdapterWhitelist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that only allows a configurable whitelist of adapters for use by a fund\ncontract AdapterWhitelist is PreCallOnIntegrationValidatePolicyBase, AddressListPolicyMixin {\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        __addToList(_comptrollerProxy, abi.decode(_encodedSettings, (address[])));\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ADAPTER_WHITELIST\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _adapter The adapter with which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address _adapter)\n        public\n        view\n        returns (bool isValid_)\n    {\n        return isInList(_comptrollerProxy, _adapter);\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (address adapter, ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, adapter);\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/utils/PreCallOnIntegrationValidatePolicyBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/PolicyBase.sol\";\n\n/// @title CallOnIntegrationPreValidatePolicyMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract for policies that only implement the PreCallOnIntegration policy hook\nabstract contract PreCallOnIntegrationValidatePolicyBase is PolicyBase {\n    /// @notice Gets the implemented PolicyHooks for a policy\n    /// @return implementedHooks_ The implemented PolicyHooks\n    function implementedHooks()\n        external\n        view\n        override\n        returns (IPolicyManager.PolicyHook[] memory implementedHooks_)\n    {\n        implementedHooks_ = new IPolicyManager.PolicyHook[](1);\n        implementedHooks_[0] = IPolicyManager.PolicyHook.PreCallOnIntegration;\n\n        return implementedHooks_;\n    }\n\n    /// @notice Helper to decode rule arguments\n    function __decodeRuleArgs(bytes memory _encodedRuleArgs)\n        internal\n        pure\n        returns (address adapter_, bytes4 selector_)\n    {\n        return abi.decode(_encodedRuleArgs, (address, bytes4));\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/GuaranteedRedemption.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../utils/FundDeployerOwnerMixin.sol\";\nimport \"./utils/PreCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title GuaranteedRedemption Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that guarantees that shares will either be continuously redeemable or\n/// redeemable within a predictable daily window by preventing trading during a configurable daily period\ncontract GuaranteedRedemption is PreCallOnIntegrationValidatePolicyBase, FundDeployerOwnerMixin {\n    using SafeMath for uint256;\n\n    event AdapterAdded(address adapter);\n\n    event AdapterRemoved(address adapter);\n\n    event FundSettingsSet(\n        address indexed comptrollerProxy,\n        uint256 startTimestamp,\n        uint256 duration\n    );\n\n    event RedemptionWindowBufferSet(uint256 prevBuffer, uint256 nextBuffer);\n\n    struct RedemptionWindow {\n        uint256 startTimestamp;\n        uint256 duration;\n    }\n\n    uint256 private constant ONE_DAY = 24 * 60 * 60;\n\n    mapping(address => bool) private adapterToCanBlockRedemption;\n    mapping(address => RedemptionWindow) private comptrollerProxyToRedemptionWindow;\n    uint256 private redemptionWindowBuffer;\n\n    constructor(\n        address _policyManager,\n        address _fundDeployer,\n        uint256 _redemptionWindowBuffer,\n        address[] memory _redemptionBlockingAdapters\n    ) public PolicyBase(_policyManager) FundDeployerOwnerMixin(_fundDeployer) {\n        redemptionWindowBuffer = _redemptionWindowBuffer;\n\n        __addRedemptionBlockingAdapters(_redemptionBlockingAdapters);\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        (uint256 startTimestamp, uint256 duration) = abi.decode(\n            _encodedSettings,\n            (uint256, uint256)\n        );\n\n        if (startTimestamp == 0) {\n            require(duration == 0, \"addFundSettings: duration must be 0 if startTimestamp is 0\");\n            return;\n        }\n\n        // Use 23 hours instead of 1 day to allow up to 1 hr of redemptionWindowBuffer\n        require(\n            duration > 0 && duration <= 23 hours,\n            \"addFundSettings: duration must be between 1 second and 23 hours\"\n        );\n\n        comptrollerProxyToRedemptionWindow[_comptrollerProxy].startTimestamp = startTimestamp;\n        comptrollerProxyToRedemptionWindow[_comptrollerProxy].duration = duration;\n\n        emit FundSettingsSet(_comptrollerProxy, startTimestamp, duration);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"GUARANTEED_REDEMPTION\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _adapter The adapter for which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address _adapter)\n        public\n        view\n        returns (bool isValid_)\n    {\n        if (!adapterCanBlockRedemption(_adapter)) {\n            return true;\n        }\n\n\n            RedemptionWindow memory redemptionWindow\n         = comptrollerProxyToRedemptionWindow[_comptrollerProxy];\n\n        // If no RedemptionWindow is set, the fund can never use redemption-blocking adapters\n        if (redemptionWindow.startTimestamp == 0) {\n            return false;\n        }\n\n        uint256 latestRedemptionWindowStart = calcLatestRedemptionWindowStart(\n            redemptionWindow.startTimestamp\n        );\n\n        // A fund can't trade during its redemption window, nor in the buffer beforehand.\n        // The lower bound is only relevant when the startTimestamp is in the future,\n        // so we check it last.\n        if (\n            block.timestamp >= latestRedemptionWindowStart.add(redemptionWindow.duration) ||\n            block.timestamp <= latestRedemptionWindowStart.sub(redemptionWindowBuffer)\n        ) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /// @notice Sets a new value for the redemptionWindowBuffer variable\n    /// @param _nextRedemptionWindowBuffer The number of seconds for the redemptionWindowBuffer\n    /// @dev The redemptionWindowBuffer is added to the beginning of the redemption window,\n    /// and should always be >= the longest potential block on redemption amongst all adapters.\n    /// (e.g., Synthetix blocks token transfers during a timelock after trading synths)\n    function setRedemptionWindowBuffer(uint256 _nextRedemptionWindowBuffer)\n        external\n        onlyFundDeployerOwner\n    {\n        uint256 prevRedemptionWindowBuffer = redemptionWindowBuffer;\n        require(\n            _nextRedemptionWindowBuffer != prevRedemptionWindowBuffer,\n            \"setRedemptionWindowBuffer: Value already set\"\n        );\n\n        redemptionWindowBuffer = _nextRedemptionWindowBuffer;\n\n        emit RedemptionWindowBufferSet(prevRedemptionWindowBuffer, _nextRedemptionWindowBuffer);\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (address adapter, ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, adapter);\n    }\n\n    // PUBLIC FUNCTIONS\n\n    /// @notice Calculates the start of the most recent redemption window\n    /// @param _startTimestamp The initial startTimestamp for the redemption window\n    /// @return latestRedemptionWindowStart_ The starting timestamp of the most recent redemption window\n    function calcLatestRedemptionWindowStart(uint256 _startTimestamp)\n        public\n        view\n        returns (uint256 latestRedemptionWindowStart_)\n    {\n        if (block.timestamp <= _startTimestamp) {\n            return _startTimestamp;\n        }\n\n        uint256 timeSinceStartTimestamp = block.timestamp.sub(_startTimestamp);\n        uint256 timeSincePeriodStart = timeSinceStartTimestamp.mod(ONE_DAY);\n\n        return block.timestamp.sub(timeSincePeriodStart);\n    }\n\n    ///////////////////////////////////////////\n    // REDEMPTION-BLOCKING ADAPTERS REGISTRY //\n    ///////////////////////////////////////////\n\n    /// @notice Add adapters which can block shares redemption\n    /// @param _adapters The addresses of adapters to be added\n    function addRedemptionBlockingAdapters(address[] calldata _adapters)\n        external\n        onlyFundDeployerOwner\n    {\n        require(\n            _adapters.length > 0,\n            \"__addRedemptionBlockingAdapters: _adapters cannot be empty\"\n        );\n\n        __addRedemptionBlockingAdapters(_adapters);\n    }\n\n    /// @notice Remove adapters which can block shares redemption\n    /// @param _adapters The addresses of adapters to be removed\n    function removeRedemptionBlockingAdapters(address[] calldata _adapters)\n        external\n        onlyFundDeployerOwner\n    {\n        require(\n            _adapters.length > 0,\n            \"removeRedemptionBlockingAdapters: _adapters cannot be empty\"\n        );\n\n        for (uint256 i; i < _adapters.length; i++) {\n            require(\n                adapterCanBlockRedemption(_adapters[i]),\n                \"removeRedemptionBlockingAdapters: adapter is not added\"\n            );\n\n            adapterToCanBlockRedemption[_adapters[i]] = false;\n\n            emit AdapterRemoved(_adapters[i]);\n        }\n    }\n\n    /// @dev Helper to mark adapters that can block shares redemption\n    function __addRedemptionBlockingAdapters(address[] memory _adapters) private {\n        for (uint256 i; i < _adapters.length; i++) {\n            require(\n                _adapters[i] != address(0),\n                \"__addRedemptionBlockingAdapters: adapter cannot be empty\"\n            );\n            require(\n                !adapterCanBlockRedemption(_adapters[i]),\n                \"__addRedemptionBlockingAdapters: adapter already added\"\n            );\n\n            adapterToCanBlockRedemption[_adapters[i]] = true;\n\n            emit AdapterAdded(_adapters[i]);\n        }\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `redemptionWindowBuffer` variable\n    /// @return redemptionWindowBuffer_ The `redemptionWindowBuffer` variable value\n    function getRedemptionWindowBuffer() external view returns (uint256 redemptionWindowBuffer_) {\n        return redemptionWindowBuffer;\n    }\n\n    /// @notice Gets the RedemptionWindow settings for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return redemptionWindow_ The RedemptionWindow settings\n    function getRedemptionWindowForFund(address _comptrollerProxy)\n        external\n        view\n        returns (RedemptionWindow memory redemptionWindow_)\n    {\n        return comptrollerProxyToRedemptionWindow[_comptrollerProxy];\n    }\n\n    /// @notice Checks whether an adapter can block shares redemption\n    /// @param _adapter The address of the adapter to check\n    /// @return canBlockRedemption_ True if the adapter can block shares redemption\n    function adapterCanBlockRedemption(address _adapter)\n        public\n        view\n        returns (bool canBlockRedemption_)\n    {\n        return adapterToCanBlockRedemption[_adapter];\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/call-on-integration/AdapterBlacklist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/PreCallOnIntegrationValidatePolicyBase.sol\";\n\n/// @title AdapterBlacklist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that disallows a configurable blacklist of adapters from use by a fund\ncontract AdapterBlacklist is PreCallOnIntegrationValidatePolicyBase, AddressListPolicyMixin {\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Add the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        __addToList(_comptrollerProxy, abi.decode(_encodedSettings, (address[])));\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ADAPTER_BLACKLIST\";\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _adapter The adapter with which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address _adapter)\n        public\n        view\n        returns (bool isValid_)\n    {\n        return !isInList(_comptrollerProxy, _adapter);\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (address adapter, ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, adapter);\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/buy-shares/InvestorWhitelist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/PreBuySharesValidatePolicyBase.sol\";\n\n/// @title InvestorWhitelist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that only allows a configurable whitelist of investors to buy shares in a fund\ncontract InvestorWhitelist is PreBuySharesValidatePolicyBase, AddressListPolicyMixin {\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Adds the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        __updateList(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"INVESTOR_WHITELIST\";\n    }\n\n    /// @notice Updates the policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function updateFundSettings(\n        address _comptrollerProxy,\n        address,\n        bytes calldata _encodedSettings\n    ) external override onlyPolicyManager {\n        __updateList(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _investor The investor for which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address _investor)\n        public\n        view\n        returns (bool isValid_)\n    {\n        return isInList(_comptrollerProxy, _investor);\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (address buyer, , , ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, buyer);\n    }\n\n    /// @dev Helper to update the investor whitelist by adding and/or removing addresses\n    function __updateList(address _comptrollerProxy, bytes memory _settingsData) private {\n        (address[] memory itemsToAdd, address[] memory itemsToRemove) = abi.decode(\n            _settingsData,\n            (address[], address[])\n        );\n\n        // If an address is in both add and remove arrays, they will not be in the final list.\n        // We do not check for uniqueness between the two arrays for efficiency.\n        if (itemsToAdd.length > 0) {\n            __addToList(_comptrollerProxy, itemsToAdd);\n        }\n        if (itemsToRemove.length > 0) {\n            __removeFromList(_comptrollerProxy, itemsToRemove);\n        }\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/buy-shares/utils/PreBuySharesValidatePolicyBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/PolicyBase.sol\";\n\n/// @title BuySharesPolicyMixin Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract for policies that only implement the PreBuyShares policy hook\nabstract contract PreBuySharesValidatePolicyBase is PolicyBase {\n    /// @notice Gets the implemented PolicyHooks for a policy\n    /// @return implementedHooks_ The implemented PolicyHooks\n    function implementedHooks()\n        external\n        view\n        override\n        returns (IPolicyManager.PolicyHook[] memory implementedHooks_)\n    {\n        implementedHooks_ = new IPolicyManager.PolicyHook[](1);\n        implementedHooks_[0] = IPolicyManager.PolicyHook.PreBuyShares;\n\n        return implementedHooks_;\n    }\n\n    /// @notice Helper to decode rule arguments\n    function __decodeRuleArgs(bytes memory _encodedArgs)\n        internal\n        pure\n        returns (\n            address buyer_,\n            uint256 investmentAmount_,\n            uint256 minSharesQuantity_,\n            uint256 gav_\n        )\n    {\n        return abi.decode(_encodedArgs, (address, uint256, uint256, uint256));\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/buy-shares/MinMaxInvestment.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"./utils/PreBuySharesValidatePolicyBase.sol\";\n\n/// @title MinMaxInvestment Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that restricts the amount of the fund's denomination asset that a user can\n/// send in a single call to buy shares in a fund\ncontract MinMaxInvestment is PreBuySharesValidatePolicyBase {\n    event FundSettingsSet(\n        address indexed comptrollerProxy,\n        uint256 minInvestmentAmount,\n        uint256 maxInvestmentAmount\n    );\n\n    struct FundSettings {\n        uint256 minInvestmentAmount;\n        uint256 maxInvestmentAmount;\n    }\n\n    mapping(address => FundSettings) private comptrollerProxyToFundSettings;\n\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Adds the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        __setFundSettings(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"MIN_MAX_INVESTMENT\";\n    }\n\n    /// @notice Updates the policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function updateFundSettings(\n        address _comptrollerProxy,\n        address,\n        bytes calldata _encodedSettings\n    ) external override onlyPolicyManager {\n        __setFundSettings(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _investmentAmount The investment amount for which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, uint256 _investmentAmount)\n        public\n        view\n        returns (bool isValid_)\n    {\n        uint256 minInvestmentAmount = comptrollerProxyToFundSettings[_comptrollerProxy]\n            .minInvestmentAmount;\n        uint256 maxInvestmentAmount = comptrollerProxyToFundSettings[_comptrollerProxy]\n            .maxInvestmentAmount;\n\n        // Both minInvestmentAmount and maxInvestmentAmount can be 0 in order to close the fund\n        // temporarily\n        if (minInvestmentAmount == 0) {\n            return _investmentAmount <= maxInvestmentAmount;\n        } else if (maxInvestmentAmount == 0) {\n            return _investmentAmount >= minInvestmentAmount;\n        }\n        return\n            _investmentAmount >= minInvestmentAmount && _investmentAmount <= maxInvestmentAmount;\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (, uint256 investmentAmount, , ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, investmentAmount);\n    }\n\n    /// @dev Helper to set the policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function __setFundSettings(address _comptrollerProxy, bytes memory _encodedSettings) private {\n        (uint256 minInvestmentAmount, uint256 maxInvestmentAmount) = abi.decode(\n            _encodedSettings,\n            (uint256, uint256)\n        );\n\n        require(\n            maxInvestmentAmount == 0 || minInvestmentAmount < maxInvestmentAmount,\n            \"__setFundSettings: minInvestmentAmount must be less than maxInvestmentAmount\"\n        );\n\n        comptrollerProxyToFundSettings[_comptrollerProxy]\n            .minInvestmentAmount = minInvestmentAmount;\n        comptrollerProxyToFundSettings[_comptrollerProxy]\n            .maxInvestmentAmount = maxInvestmentAmount;\n\n        emit FundSettingsSet(_comptrollerProxy, minInvestmentAmount, maxInvestmentAmount);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the min and max investment amount for a given fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @return fundSettings_ The fund settings\n    function getFundSettings(address _comptrollerProxy)\n        external\n        view\n        returns (FundSettings memory fundSettings_)\n    {\n        return comptrollerProxyToFundSettings[_comptrollerProxy];\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/buy-shares/BuySharesCallerWhitelist.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/AddressListPolicyMixin.sol\";\nimport \"./utils/BuySharesSetupPolicyBase.sol\";\n\n/// @title BuySharesCallerWhitelist Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A policy that only allows a configurable whitelist of buyShares callers for a fund\ncontract BuySharesCallerWhitelist is BuySharesSetupPolicyBase, AddressListPolicyMixin {\n    constructor(address _policyManager) public PolicyBase(_policyManager) {}\n\n    /// @notice Adds the initial policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _encodedSettings)\n        external\n        override\n        onlyPolicyManager\n    {\n        __updateList(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Provides a constant string identifier for a policy\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"BUY_SHARES_CALLER_WHITELIST\";\n    }\n\n    /// @notice Updates the policy settings for a fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedSettings Encoded settings to apply to a fund\n    function updateFundSettings(\n        address _comptrollerProxy,\n        address,\n        bytes calldata _encodedSettings\n    ) external override onlyPolicyManager {\n        __updateList(_comptrollerProxy, _encodedSettings);\n    }\n\n    /// @notice Checks whether a particular condition passes the rule for a particular fund\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _buySharesCaller The buyShares caller for which to check the rule\n    /// @return isValid_ True if the rule passes\n    function passesRule(address _comptrollerProxy, address _buySharesCaller)\n        public\n        view\n        returns (bool isValid_)\n    {\n        return isInList(_comptrollerProxy, _buySharesCaller);\n    }\n\n    /// @notice Apply the rule with the specified parameters of a PolicyHook\n    /// @param _comptrollerProxy The fund's ComptrollerProxy address\n    /// @param _encodedArgs Encoded args with which to validate the rule\n    /// @return isValid_ True if the rule passes\n    function validateRule(\n        address _comptrollerProxy,\n        address,\n        IPolicyManager.PolicyHook,\n        bytes calldata _encodedArgs\n    ) external override returns (bool isValid_) {\n        (address caller, , ) = __decodeRuleArgs(_encodedArgs);\n\n        return passesRule(_comptrollerProxy, caller);\n    }\n\n    /// @dev Helper to update the whitelist by adding and/or removing addresses\n    function __updateList(address _comptrollerProxy, bytes memory _settingsData) private {\n        (address[] memory itemsToAdd, address[] memory itemsToRemove) = abi.decode(\n            _settingsData,\n            (address[], address[])\n        );\n\n        // If an address is in both add and remove arrays, they will not be in the final list.\n        // We do not check for uniqueness between the two arrays for efficiency.\n        if (itemsToAdd.length > 0) {\n            __addToList(_comptrollerProxy, itemsToAdd);\n        }\n        if (itemsToRemove.length > 0) {\n            __removeFromList(_comptrollerProxy, itemsToRemove);\n        }\n    }\n}\n"
      },
      "contracts/release/extensions/policy-manager/policies/buy-shares/utils/BuySharesSetupPolicyBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/PolicyBase.sol\";\n\n/// @title BuySharesSetupPolicyBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mixin contract for policies that only implement the BuySharesSetup policy hook\nabstract contract BuySharesSetupPolicyBase is PolicyBase {\n    /// @notice Gets the implemented PolicyHooks for a policy\n    /// @return implementedHooks_ The implemented PolicyHooks\n    function implementedHooks()\n        external\n        view\n        override\n        returns (IPolicyManager.PolicyHook[] memory implementedHooks_)\n    {\n        implementedHooks_ = new IPolicyManager.PolicyHook[](1);\n        implementedHooks_[0] = IPolicyManager.PolicyHook.BuySharesSetup;\n\n        return implementedHooks_;\n    }\n\n    /// @notice Helper to decode rule arguments\n    function __decodeRuleArgs(bytes memory _encodedArgs)\n        internal\n        pure\n        returns (\n            address caller_,\n            uint256[] memory investmentAmounts_,\n            uint256 gav_\n        )\n    {\n        return abi.decode(_encodedArgs, (address, uint256[], uint256));\n    }\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/TrackedAssetsAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../core/fund/vault/VaultLib.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title TrackedAssetsAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter to add tracked assets to a fund (useful e.g. to handle token airdrops)\ncontract TrackedAssetsAdapter is AdapterBase {\n    constructor(address _integrationManager) public AdapterBase(_integrationManager) {}\n\n    /// @notice Add multiple assets to the Vault's list of tracked assets\n    /// @dev No need to perform any validation or implement any logic\n    function addTrackedAssets(\n        address,\n        bytes calldata,\n        bytes calldata\n    ) external view {}\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"TRACKED_ASSETS\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        require(\n            _selector == ADD_TRACKED_ASSETS_SELECTOR,\n            \"parseAssetsForMethod: _selector invalid\"\n        );\n\n        incomingAssets_ = __decodeCallArgs(_encodedCallArgs);\n\n        minIncomingAssetAmounts_ = new uint256[](incomingAssets_.length);\n        for (uint256 i; i < minIncomingAssetAmounts_.length; i++) {\n            minIncomingAssetAmounts_[i] = 1;\n        }\n\n        return (\n            spendAssetsHandleType_,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode the encoded call arguments\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (address[] memory incomingAssets_)\n    {\n        return abi.decode(_encodedCallArgs, (address[]));\n    }\n}\n"
      },
      "contracts/persistent/vault/VaultProxy.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./utils/ProxiableVaultLib.sol\";\n\n/// @title VaultProxy Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A proxy contract for all VaultProxy instances, slightly modified from EIP-1822\n/// @dev Adapted from the recommended implementation of a Proxy in EIP-1822, updated for solc 0.6.12,\n/// and using the EIP-1967 storage slot for the proxiable implementation.\n/// i.e., `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`, which is\n/// \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\"\n/// See: https://eips.ethereum.org/EIPS/eip-1822\ncontract VaultProxy {\n    constructor(bytes memory _constructData, address _vaultLib) public {\n        // \"0x027b9570e9fedc1a80b937ae9a06861e5faef3992491af30b684a64b3fbec7a5\" corresponds to\n        // `bytes32(keccak256('mln.proxiable.vaultlib'))`\n        require(\n            bytes32(0x027b9570e9fedc1a80b937ae9a06861e5faef3992491af30b684a64b3fbec7a5) ==\n                ProxiableVaultLib(_vaultLib).proxiableUUID(),\n            \"constructor: _vaultLib not compatible\"\n        );\n\n        assembly {\n            // solium-disable-line\n            sstore(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, _vaultLib)\n        }\n\n        (bool success, bytes memory returnData) = _vaultLib.delegatecall(_constructData); // solium-disable-line\n        require(success, string(returnData));\n    }\n\n    fallback() external payable {\n        assembly {\n            // solium-disable-line\n            let contractLogic := sload(\n                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\n            )\n            calldatacopy(0x0, 0x0, calldatasize())\n            let success := delegatecall(\n                sub(gas(), 10000),\n                contractLogic,\n                0x0,\n                calldatasize(),\n                0,\n                0\n            )\n            let retSz := returndatasize()\n            returndatacopy(0, 0, retSz)\n            switch success\n                case 0 {\n                    revert(0, retSz)\n                }\n                default {\n                    return(0, retSz)\n                }\n        }\n    }\n}\n"
      },
      "contracts/persistent/dispatcher/Dispatcher.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/IMigrationHookHandler.sol\";\nimport \"../utils/IMigratableVault.sol\";\nimport \"../vault/VaultProxy.sol\";\nimport \"./IDispatcher.sol\";\n\n/// @title Dispatcher Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice The top-level contract linking multiple releases.\n/// It handles the deployment of new VaultProxy instances,\n/// and the regulation of fund migration from a previous release to the current one.\n/// It can also be referred to for access-control based on this contract's owner.\n/// @dev DO NOT EDIT CONTRACT\ncontract Dispatcher is IDispatcher {\n    event CurrentFundDeployerSet(address prevFundDeployer, address nextFundDeployer);\n\n    event MigrationCancelled(\n        address indexed vaultProxy,\n        address indexed prevFundDeployer,\n        address indexed nextFundDeployer,\n        address nextVaultAccessor,\n        address nextVaultLib,\n        uint256 executableTimestamp\n    );\n\n    event MigrationExecuted(\n        address indexed vaultProxy,\n        address indexed prevFundDeployer,\n        address indexed nextFundDeployer,\n        address nextVaultAccessor,\n        address nextVaultLib,\n        uint256 executableTimestamp\n    );\n\n    event MigrationSignaled(\n        address indexed vaultProxy,\n        address indexed prevFundDeployer,\n        address indexed nextFundDeployer,\n        address nextVaultAccessor,\n        address nextVaultLib,\n        uint256 executableTimestamp\n    );\n\n    event MigrationTimelockSet(uint256 prevTimelock, uint256 nextTimelock);\n\n    event NominatedOwnerSet(address indexed nominatedOwner);\n\n    event NominatedOwnerRemoved(address indexed nominatedOwner);\n\n    event OwnershipTransferred(address indexed prevOwner, address indexed nextOwner);\n\n    event MigrationInCancelHookFailed(\n        bytes failureReturnData,\n        address indexed vaultProxy,\n        address indexed prevFundDeployer,\n        address indexed nextFundDeployer,\n        address nextVaultAccessor,\n        address nextVaultLib\n    );\n\n    event MigrationOutHookFailed(\n        bytes failureReturnData,\n        IMigrationHookHandler.MigrationOutHook hook,\n        address indexed vaultProxy,\n        address indexed prevFundDeployer,\n        address indexed nextFundDeployer,\n        address nextVaultAccessor,\n        address nextVaultLib\n    );\n\n    event SharesTokenSymbolSet(string _nextSymbol);\n\n    event VaultProxyDeployed(\n        address indexed fundDeployer,\n        address indexed owner,\n        address vaultProxy,\n        address indexed vaultLib,\n        address vaultAccessor,\n        string fundName\n    );\n\n    struct MigrationRequest {\n        address nextFundDeployer;\n        address nextVaultAccessor;\n        address nextVaultLib;\n        uint256 executableTimestamp;\n    }\n\n    address private currentFundDeployer;\n    address private nominatedOwner;\n    address private owner;\n    uint256 private migrationTimelock;\n    string private sharesTokenSymbol;\n    mapping(address => address) private vaultProxyToFundDeployer;\n    mapping(address => MigrationRequest) private vaultProxyToMigrationRequest;\n\n    modifier onlyCurrentFundDeployer() {\n        require(\n            msg.sender == currentFundDeployer,\n            \"Only the current FundDeployer can call this function\"\n        );\n        _;\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == owner, \"Only the contract owner can call this function\");\n        _;\n    }\n\n    constructor() public {\n        migrationTimelock = 2 days;\n        owner = msg.sender;\n        sharesTokenSymbol = \"ENZF\";\n    }\n\n    /////////////\n    // GENERAL //\n    /////////////\n\n    /// @notice Sets a new `symbol` value for VaultProxy instances\n    /// @param _nextSymbol The symbol value to set\n    function setSharesTokenSymbol(string calldata _nextSymbol) external override onlyOwner {\n        sharesTokenSymbol = _nextSymbol;\n\n        emit SharesTokenSymbolSet(_nextSymbol);\n    }\n\n    ////////////////////\n    // ACCESS CONTROL //\n    ////////////////////\n\n    /// @notice Claim ownership of the contract\n    function claimOwnership() external override {\n        address nextOwner = nominatedOwner;\n        require(\n            msg.sender == nextOwner,\n            \"claimOwnership: Only the nominatedOwner can call this function\"\n        );\n\n        delete nominatedOwner;\n\n        address prevOwner = owner;\n        owner = nextOwner;\n\n        emit OwnershipTransferred(prevOwner, nextOwner);\n    }\n\n    /// @notice Revoke the nomination of a new contract owner\n    function removeNominatedOwner() external override onlyOwner {\n        address removedNominatedOwner = nominatedOwner;\n        require(\n            removedNominatedOwner != address(0),\n            \"removeNominatedOwner: There is no nominated owner\"\n        );\n\n        delete nominatedOwner;\n\n        emit NominatedOwnerRemoved(removedNominatedOwner);\n    }\n\n    /// @notice Set a new FundDeployer for use within the contract\n    /// @param _nextFundDeployer The address of the FundDeployer contract\n    function setCurrentFundDeployer(address _nextFundDeployer) external override onlyOwner {\n        require(\n            _nextFundDeployer != address(0),\n            \"setCurrentFundDeployer: _nextFundDeployer cannot be empty\"\n        );\n        require(\n            __isContract(_nextFundDeployer),\n            \"setCurrentFundDeployer: Non-contract _nextFundDeployer\"\n        );\n\n        address prevFundDeployer = currentFundDeployer;\n        require(\n            _nextFundDeployer != prevFundDeployer,\n            \"setCurrentFundDeployer: _nextFundDeployer is already currentFundDeployer\"\n        );\n\n        currentFundDeployer = _nextFundDeployer;\n\n        emit CurrentFundDeployerSet(prevFundDeployer, _nextFundDeployer);\n    }\n\n    /// @notice Nominate a new contract owner\n    /// @param _nextNominatedOwner The account to nominate\n    /// @dev Does not prohibit overwriting the current nominatedOwner\n    function setNominatedOwner(address _nextNominatedOwner) external override onlyOwner {\n        require(\n            _nextNominatedOwner != address(0),\n            \"setNominatedOwner: _nextNominatedOwner cannot be empty\"\n        );\n        require(\n            _nextNominatedOwner != owner,\n            \"setNominatedOwner: _nextNominatedOwner is already the owner\"\n        );\n        require(\n            _nextNominatedOwner != nominatedOwner,\n            \"setNominatedOwner: _nextNominatedOwner is already nominated\"\n        );\n\n        nominatedOwner = _nextNominatedOwner;\n\n        emit NominatedOwnerSet(_nextNominatedOwner);\n    }\n\n    /// @dev Helper to check whether an address is a deployed contract\n    function __isContract(address _who) private view returns (bool isContract_) {\n        uint256 size;\n        assembly {\n            size := extcodesize(_who)\n        }\n\n        return size > 0;\n    }\n\n    ////////////////\n    // DEPLOYMENT //\n    ////////////////\n\n    /// @notice Deploys a VaultProxy\n    /// @param _vaultLib The VaultLib library with which to instantiate the VaultProxy\n    /// @param _owner The account to set as the VaultProxy's owner\n    /// @param _vaultAccessor The account to set as the VaultProxy's permissioned accessor\n    /// @param _fundName The name of the fund\n    /// @dev Input validation should be handled by the VaultProxy during deployment\n    function deployVaultProxy(\n        address _vaultLib,\n        address _owner,\n        address _vaultAccessor,\n        string calldata _fundName\n    ) external override onlyCurrentFundDeployer returns (address vaultProxy_) {\n        require(__isContract(_vaultAccessor), \"deployVaultProxy: Non-contract _vaultAccessor\");\n\n        bytes memory constructData = abi.encodeWithSelector(\n            IMigratableVault.init.selector,\n            _owner,\n            _vaultAccessor,\n            _fundName\n        );\n        vaultProxy_ = address(new VaultProxy(constructData, _vaultLib));\n\n        address fundDeployer = msg.sender;\n        vaultProxyToFundDeployer[vaultProxy_] = fundDeployer;\n\n        emit VaultProxyDeployed(\n            fundDeployer,\n            _owner,\n            vaultProxy_,\n            _vaultLib,\n            _vaultAccessor,\n            _fundName\n        );\n\n        return vaultProxy_;\n    }\n\n    ////////////////\n    // MIGRATIONS //\n    ////////////////\n\n    /// @notice Cancels a pending migration request\n    /// @param _vaultProxy The VaultProxy contract for which to cancel the migration request\n    /// @param _bypassFailure True if a failure in either migration hook should be ignored\n    /// @dev Because this function must also be callable by a permissioned migrator, it has an\n    /// extra migration hook to the nextFundDeployer for the case where cancelMigration()\n    /// is called directly (rather than via the nextFundDeployer).\n    function cancelMigration(address _vaultProxy, bool _bypassFailure) external override {\n        MigrationRequest memory request = vaultProxyToMigrationRequest[_vaultProxy];\n        address nextFundDeployer = request.nextFundDeployer;\n        require(nextFundDeployer != address(0), \"cancelMigration: No migration request exists\");\n\n        // TODO: confirm that if canMigrate() does not exist but the caller is a valid FundDeployer, this still works.\n        require(\n            msg.sender == nextFundDeployer || IMigratableVault(_vaultProxy).canMigrate(msg.sender),\n            \"cancelMigration: Not an allowed caller\"\n        );\n\n        address prevFundDeployer = vaultProxyToFundDeployer[_vaultProxy];\n        address nextVaultAccessor = request.nextVaultAccessor;\n        address nextVaultLib = request.nextVaultLib;\n        uint256 executableTimestamp = request.executableTimestamp;\n\n        delete vaultProxyToMigrationRequest[_vaultProxy];\n\n        __invokeMigrationOutHook(\n            IMigrationHookHandler.MigrationOutHook.PostCancel,\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            _bypassFailure\n        );\n        __invokeMigrationInCancelHook(\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            _bypassFailure\n        );\n\n        emit MigrationCancelled(\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            executableTimestamp\n        );\n    }\n\n    /// @notice Executes a pending migration request\n    /// @param _vaultProxy The VaultProxy contract for which to execute the migration request\n    /// @param _bypassFailure True if a failure in either migration hook should be ignored\n    function executeMigration(address _vaultProxy, bool _bypassFailure) external override {\n        MigrationRequest memory request = vaultProxyToMigrationRequest[_vaultProxy];\n        address nextFundDeployer = request.nextFundDeployer;\n        require(\n            nextFundDeployer != address(0),\n            \"executeMigration: No migration request exists for _vaultProxy\"\n        );\n        require(\n            msg.sender == nextFundDeployer,\n            \"executeMigration: Only the target FundDeployer can call this function\"\n        );\n        require(\n            nextFundDeployer == currentFundDeployer,\n            \"executeMigration: The target FundDeployer is no longer the current FundDeployer\"\n        );\n        uint256 executableTimestamp = request.executableTimestamp;\n        require(\n            block.timestamp >= executableTimestamp,\n            \"executeMigration: The migration timelock has not elapsed\"\n        );\n\n        address prevFundDeployer = vaultProxyToFundDeployer[_vaultProxy];\n        address nextVaultAccessor = request.nextVaultAccessor;\n        address nextVaultLib = request.nextVaultLib;\n\n        __invokeMigrationOutHook(\n            IMigrationHookHandler.MigrationOutHook.PreMigrate,\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            _bypassFailure\n        );\n\n        // Upgrade the VaultProxy to a new VaultLib and update the accessor via the new VaultLib\n        IMigratableVault(_vaultProxy).setVaultLib(nextVaultLib);\n        IMigratableVault(_vaultProxy).setAccessor(nextVaultAccessor);\n\n        // Update the FundDeployer that migrated the VaultProxy\n        vaultProxyToFundDeployer[_vaultProxy] = nextFundDeployer;\n\n        // Remove the migration request\n        delete vaultProxyToMigrationRequest[_vaultProxy];\n\n        __invokeMigrationOutHook(\n            IMigrationHookHandler.MigrationOutHook.PostMigrate,\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            _bypassFailure\n        );\n\n        emit MigrationExecuted(\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            nextVaultAccessor,\n            nextVaultLib,\n            executableTimestamp\n        );\n    }\n\n    /// @notice Sets a new migration timelock\n    /// @param _nextTimelock The number of seconds for the new timelock\n    function setMigrationTimelock(uint256 _nextTimelock) external override onlyOwner {\n        uint256 prevTimelock = migrationTimelock;\n        require(\n            _nextTimelock != prevTimelock,\n            \"setMigrationTimelock: _nextTimelock is the current timelock\"\n        );\n\n        migrationTimelock = _nextTimelock;\n\n        emit MigrationTimelockSet(prevTimelock, _nextTimelock);\n    }\n\n    /// @notice Signals a migration by creating a migration request\n    /// @param _vaultProxy The VaultProxy contract for which to signal migration\n    /// @param _nextVaultAccessor The account that will be the next `accessor` on the VaultProxy\n    /// @param _nextVaultLib The next VaultLib library contract address to set on the VaultProxy\n    /// @param _bypassFailure True if a failure in either migration hook should be ignored\n    function signalMigration(\n        address _vaultProxy,\n        address _nextVaultAccessor,\n        address _nextVaultLib,\n        bool _bypassFailure\n    ) external override onlyCurrentFundDeployer {\n        require(\n            __isContract(_nextVaultAccessor),\n            \"signalMigration: Non-contract _nextVaultAccessor\"\n        );\n\n        address prevFundDeployer = vaultProxyToFundDeployer[_vaultProxy];\n        require(prevFundDeployer != address(0), \"signalMigration: _vaultProxy does not exist\");\n\n        address nextFundDeployer = msg.sender;\n        require(\n            nextFundDeployer != prevFundDeployer,\n            \"signalMigration: Can only migrate to a new FundDeployer\"\n        );\n\n        __invokeMigrationOutHook(\n            IMigrationHookHandler.MigrationOutHook.PreSignal,\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            _nextVaultAccessor,\n            _nextVaultLib,\n            _bypassFailure\n        );\n\n        uint256 executableTimestamp = block.timestamp + migrationTimelock;\n        vaultProxyToMigrationRequest[_vaultProxy] = MigrationRequest({\n            nextFundDeployer: nextFundDeployer,\n            nextVaultAccessor: _nextVaultAccessor,\n            nextVaultLib: _nextVaultLib,\n            executableTimestamp: executableTimestamp\n        });\n\n        __invokeMigrationOutHook(\n            IMigrationHookHandler.MigrationOutHook.PostSignal,\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            _nextVaultAccessor,\n            _nextVaultLib,\n            _bypassFailure\n        );\n\n        emit MigrationSignaled(\n            _vaultProxy,\n            prevFundDeployer,\n            nextFundDeployer,\n            _nextVaultAccessor,\n            _nextVaultLib,\n            executableTimestamp\n        );\n    }\n\n    /// @dev Helper to invoke a MigrationInCancelHook on the next FundDeployer being \"migrated in\" to,\n    /// which can optionally be implemented on the FundDeployer\n    function __invokeMigrationInCancelHook(\n        address _vaultProxy,\n        address _prevFundDeployer,\n        address _nextFundDeployer,\n        address _nextVaultAccessor,\n        address _nextVaultLib,\n        bool _bypassFailure\n    ) private {\n        (bool success, bytes memory returnData) = _nextFundDeployer.call(\n            abi.encodeWithSelector(\n                IMigrationHookHandler.invokeMigrationInCancelHook.selector,\n                _vaultProxy,\n                _prevFundDeployer,\n                _nextVaultAccessor,\n                _nextVaultLib\n            )\n        );\n        if (!success) {\n            require(\n                _bypassFailure,\n                string(abi.encodePacked(\"MigrationOutCancelHook: \", returnData))\n            );\n\n            emit MigrationInCancelHookFailed(\n                returnData,\n                _vaultProxy,\n                _prevFundDeployer,\n                _nextFundDeployer,\n                _nextVaultAccessor,\n                _nextVaultLib\n            );\n        }\n    }\n\n    /// @dev Helper to invoke a IMigrationHookHandler.MigrationOutHook on the previous FundDeployer being \"migrated out\" of,\n    /// which can optionally be implemented on the FundDeployer\n    function __invokeMigrationOutHook(\n        IMigrationHookHandler.MigrationOutHook _hook,\n        address _vaultProxy,\n        address _prevFundDeployer,\n        address _nextFundDeployer,\n        address _nextVaultAccessor,\n        address _nextVaultLib,\n        bool _bypassFailure\n    ) private {\n        (bool success, bytes memory returnData) = _prevFundDeployer.call(\n            abi.encodeWithSelector(\n                IMigrationHookHandler.invokeMigrationOutHook.selector,\n                _hook,\n                _vaultProxy,\n                _nextFundDeployer,\n                _nextVaultAccessor,\n                _nextVaultLib\n            )\n        );\n        if (!success) {\n            require(\n                _bypassFailure,\n                string(abi.encodePacked(__migrationOutHookFailureReasonPrefix(_hook), returnData))\n            );\n\n            emit MigrationOutHookFailed(\n                returnData,\n                _hook,\n                _vaultProxy,\n                _prevFundDeployer,\n                _nextFundDeployer,\n                _nextVaultAccessor,\n                _nextVaultLib\n            );\n        }\n    }\n\n    /// @dev Helper to return a revert reason string prefix for a given MigrationOutHook\n    function __migrationOutHookFailureReasonPrefix(IMigrationHookHandler.MigrationOutHook _hook)\n        private\n        pure\n        returns (string memory failureReasonPrefix_)\n    {\n        if (_hook == IMigrationHookHandler.MigrationOutHook.PreSignal) {\n            return \"MigrationOutHook.PreSignal: \";\n        }\n        if (_hook == IMigrationHookHandler.MigrationOutHook.PostSignal) {\n            return \"MigrationOutHook.PostSignal: \";\n        }\n        if (_hook == IMigrationHookHandler.MigrationOutHook.PreMigrate) {\n            return \"MigrationOutHook.PreMigrate: \";\n        }\n        if (_hook == IMigrationHookHandler.MigrationOutHook.PostMigrate) {\n            return \"MigrationOutHook.PostMigrate: \";\n        }\n        if (_hook == IMigrationHookHandler.MigrationOutHook.PostCancel) {\n            return \"MigrationOutHook.PostCancel: \";\n        }\n\n        return \"\";\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    // Provides several potentially helpful getters that are not strictly necessary\n\n    /// @notice Gets the current FundDeployer that is allowed to deploy and migrate funds\n    /// @return currentFundDeployer_ The current FundDeployer contract address\n    function getCurrentFundDeployer()\n        external\n        view\n        override\n        returns (address currentFundDeployer_)\n    {\n        return currentFundDeployer;\n    }\n\n    /// @notice Gets the FundDeployer with which a given VaultProxy is associated\n    /// @param _vaultProxy The VaultProxy instance\n    /// @return fundDeployer_ The FundDeployer contract address\n    function getFundDeployerForVaultProxy(address _vaultProxy)\n        external\n        view\n        override\n        returns (address fundDeployer_)\n    {\n        return vaultProxyToFundDeployer[_vaultProxy];\n    }\n\n    /// @notice Gets the details of a pending migration request for a given VaultProxy\n    /// @param _vaultProxy The VaultProxy instance\n    /// @return nextFundDeployer_ The FundDeployer contract address from which the migration\n    /// request was made\n    /// @return nextVaultAccessor_ The account that will be the next `accessor` on the VaultProxy\n    /// @return nextVaultLib_ The next VaultLib library contract address to set on the VaultProxy\n    /// @return executableTimestamp_ The timestamp at which the migration request can be executed\n    function getMigrationRequestDetailsForVaultProxy(address _vaultProxy)\n        external\n        view\n        override\n        returns (\n            address nextFundDeployer_,\n            address nextVaultAccessor_,\n            address nextVaultLib_,\n            uint256 executableTimestamp_\n        )\n    {\n        MigrationRequest memory r = vaultProxyToMigrationRequest[_vaultProxy];\n        if (r.executableTimestamp > 0) {\n            return (\n                r.nextFundDeployer,\n                r.nextVaultAccessor,\n                r.nextVaultLib,\n                r.executableTimestamp\n            );\n        }\n    }\n\n    /// @notice Gets the amount of time that must pass between signaling and executing a migration\n    /// @return migrationTimelock_ The timelock value (in seconds)\n    function getMigrationTimelock() external view override returns (uint256 migrationTimelock_) {\n        return migrationTimelock;\n    }\n\n    /// @notice Gets the account that is nominated to be the next owner of this contract\n    /// @return nominatedOwner_ The account that is nominated to be the owner\n    function getNominatedOwner() external view override returns (address nominatedOwner_) {\n        return nominatedOwner;\n    }\n\n    /// @notice Gets the owner of this contract\n    /// @return owner_ The account that is the owner\n    function getOwner() external view override returns (address owner_) {\n        return owner;\n    }\n\n    /// @notice Gets the shares token `symbol` value for use in VaultProxy instances\n    /// @return sharesTokenSymbol_ The `symbol` value\n    function getSharesTokenSymbol()\n        external\n        view\n        override\n        returns (string memory sharesTokenSymbol_)\n    {\n        return sharesTokenSymbol;\n    }\n\n    /// @notice Gets the time remaining until the migration request of a given VaultProxy can be executed\n    /// @param _vaultProxy The VaultProxy instance\n    /// @return secondsRemaining_ The number of seconds remaining on the timelock\n    function getTimelockRemainingForMigrationRequest(address _vaultProxy)\n        external\n        view\n        override\n        returns (uint256 secondsRemaining_)\n    {\n        uint256 executableTimestamp = vaultProxyToMigrationRequest[_vaultProxy]\n            .executableTimestamp;\n        if (executableTimestamp == 0) {\n            return 0;\n        }\n\n        if (block.timestamp >= executableTimestamp) {\n            return 0;\n        }\n\n        return executableTimestamp - block.timestamp;\n    }\n\n    /// @notice Checks whether a migration request that is executable exists for a given VaultProxy\n    /// @param _vaultProxy The VaultProxy instance\n    /// @return hasExecutableRequest_ True if a migration request exists and is executable\n    function hasExecutableMigrationRequest(address _vaultProxy)\n        external\n        view\n        override\n        returns (bool hasExecutableRequest_)\n    {\n        uint256 executableTimestamp = vaultProxyToMigrationRequest[_vaultProxy]\n            .executableTimestamp;\n\n        return executableTimestamp > 0 && block.timestamp >= executableTimestamp;\n    }\n\n    /// @notice Checks whether a migration request exists for a given VaultProxy\n    /// @param _vaultProxy The VaultProxy instance\n    /// @return hasMigrationRequest_ True if a migration request exists\n    function hasMigrationRequest(address _vaultProxy)\n        external\n        view\n        override\n        returns (bool hasMigrationRequest_)\n    {\n        return vaultProxyToMigrationRequest[_vaultProxy].executableTimestamp > 0;\n    }\n}\n"
      },
      "contracts/mocks/MockVaultLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../persistent/vault/VaultLibBaseCore.sol\";\n\n/// @title MockVaultLib Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice A mock VaultLib implementation that only extends VaultLibBaseCore\ncontract MockVaultLib is VaultLibBaseCore {\n    function getAccessor() external view returns (address) {\n        return accessor;\n    }\n\n    function getCreator() external view returns (address) {\n        return creator;\n    }\n\n    function getMigrator() external view returns (address) {\n        return migrator;\n    }\n\n    function getOwner() external view returns (address) {\n        return owner;\n    }\n}\n"
      },
      "contracts/release/interfaces/ICERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity ^0.6.12;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title ICERC20 Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Minimal interface for interactions with Compound tokens (cTokens)\ninterface ICERC20 is IERC20 {\n    function decimals() external view returns (uint8);\n\n    function mint(uint256) external returns (uint256);\n\n    function redeem(uint256) external returns (uint256);\n\n    function exchangeRateStored() external view returns (uint256);\n\n    function underlying() external returns (address);\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/feeds/CompoundPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/ICERC20.sol\";\nimport \"../../../utils/DispatcherOwnerMixin.sol\";\nimport \"../IDerivativePriceFeed.sol\";\n\n/// @title CompoundPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Price source oracle for Compound Tokens (cTokens)\ncontract CompoundPriceFeed is IDerivativePriceFeed, DispatcherOwnerMixin {\n    using SafeMath for uint256;\n\n    event CTokenAdded(address indexed cToken, address indexed token);\n\n    uint256 private constant CTOKEN_RATE_DIVISOR = 10**18;\n\n    mapping(address => address) private cTokenToToken;\n\n    constructor(\n        address _dispatcher,\n        address _weth,\n        address _ceth,\n        address[] memory cERC20Tokens\n    ) public DispatcherOwnerMixin(_dispatcher) {\n        // Set cEth\n        cTokenToToken[_ceth] = _weth;\n        emit CTokenAdded(_ceth, _weth);\n\n        // Set any other cTokens\n        if (cERC20Tokens.length > 0) {\n            __addCERC20Tokens(cERC20Tokens);\n        }\n    }\n\n    /// @notice Converts a given amount of a derivative to its underlying asset values\n    /// @param _derivative The derivative to convert\n    /// @param _derivativeAmount The amount of the derivative to convert\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The amount of each underlying asset for the equivalent derivative amount\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        underlyings_ = new address[](1);\n        underlyings_[0] = cTokenToToken[_derivative];\n        require(underlyings_[0] != address(0), \"calcUnderlyingValues: Unsupported derivative\");\n\n        underlyingAmounts_ = new uint256[](1);\n        // Returns a rate scaled to 10^18\n        underlyingAmounts_[0] = _derivativeAmount\n            .mul(ICERC20(_derivative).exchangeRateStored())\n            .div(CTOKEN_RATE_DIVISOR);\n\n        return (underlyings_, underlyingAmounts_);\n    }\n\n    /// @notice Checks if an asset is supported by the price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is supported\n    function isSupportedAsset(address _asset) external view override returns (bool isSupported_) {\n        return cTokenToToken[_asset] != address(0);\n    }\n\n    //////////////////////\n    // CTOKENS REGISTRY //\n    //////////////////////\n\n    /// @notice Adds cTokens to the price feed\n    /// @param _cTokens cTokens to add\n    /// @dev Only allows CERC20 tokens. CEther is set in the constructor.\n    function addCTokens(address[] calldata _cTokens) external onlyDispatcherOwner {\n        __addCERC20Tokens(_cTokens);\n    }\n\n    /// @dev Helper to add cTokens\n    function __addCERC20Tokens(address[] memory _cTokens) private {\n        require(_cTokens.length > 0, \"__addCTokens: Empty _cTokens\");\n\n        for (uint256 i; i < _cTokens.length; i++) {\n            require(cTokenToToken[_cTokens[i]] == address(0), \"__addCTokens: Value already set\");\n\n            address token = ICERC20(_cTokens[i]).underlying();\n            cTokenToToken[_cTokens[i]] = token;\n\n            emit CTokenAdded(_cTokens[i], token);\n        }\n    }\n\n    ////////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Returns the underlying asset of a given cToken\n    /// @param _cToken The cToken for which to get the underlying asset\n    /// @return token_ The underlying token\n    function getTokenFromCToken(address _cToken) public view returns (address token_) {\n        return cTokenToToken[_cToken];\n    }\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/CompoundAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../infrastructure/price-feeds/derivatives/feeds/CompoundPriceFeed.sol\";\nimport \"../../../../interfaces/ICERC20.sol\";\nimport \"../../../../interfaces/ICEther.sol\";\nimport \"../../../../interfaces/IWETH.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title CompoundAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for Compound <https://compound.finance/>\ncontract CompoundAdapter is AdapterBase {\n    address private immutable COMPOUND_PRICE_FEED;\n    address private immutable WETH_TOKEN;\n\n    constructor(\n        address _integrationManager,\n        address _compoundPriceFeed,\n        address _wethToken\n    ) public AdapterBase(_integrationManager) {\n        COMPOUND_PRICE_FEED = _compoundPriceFeed;\n        WETH_TOKEN = _wethToken;\n    }\n\n    /// @dev Needed to receive ETH during cEther lend/redeem\n    receive() external payable {}\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ An identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"COMPOUND\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        if (_selector == LEND_SELECTOR) {\n            (address cToken, uint256 tokenAmount, uint256 minCTokenAmount) = __decodeCallArgs(\n                _encodedCallArgs\n            );\n            address token = CompoundPriceFeed(COMPOUND_PRICE_FEED).getTokenFromCToken(cToken);\n            require(token != address(0), \"parseAssetsForMethod: Unsupported cToken\");\n\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = token;\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = tokenAmount;\n\n            incomingAssets_ = new address[](1);\n            incomingAssets_[0] = cToken;\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minCTokenAmount;\n        } else if (_selector == REDEEM_SELECTOR) {\n            (address cToken, uint256 cTokenAmount, uint256 minTokenAmount) = __decodeCallArgs(\n                _encodedCallArgs\n            );\n            address token = CompoundPriceFeed(COMPOUND_PRICE_FEED).getTokenFromCToken(cToken);\n            require(token != address(0), \"parseAssetsForMethod: Unsupported cToken\");\n\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = cToken;\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = cTokenAmount;\n\n            incomingAssets_ = new address[](1);\n            incomingAssets_[0] = token;\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minTokenAmount;\n        } else {\n            revert(\"parseAssetsForMethod: _selector invalid\");\n        }\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Lends an amount of a token to Compound\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function lend(\n        address _vaultProxy,\n        bytes calldata,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        // More efficient to parse all from _encodedAssetTransferArgs\n        (\n            ,\n            address[] memory spendAssets,\n            uint256[] memory spendAssetAmounts,\n            address[] memory incomingAssets\n        ) = __decodeEncodedAssetTransferArgs(_encodedAssetTransferArgs);\n\n        if (spendAssets[0] == WETH_TOKEN) {\n            IWETH(WETH_TOKEN).withdraw(spendAssetAmounts[0]);\n            ICEther(incomingAssets[0]).mint{value: spendAssetAmounts[0]}();\n        } else {\n            __approveMaxAsNeeded(spendAssets[0], incomingAssets[0], spendAssetAmounts[0]);\n            ICERC20(incomingAssets[0]).mint(spendAssetAmounts[0]);\n        }\n    }\n\n    /// @notice Redeems an amount of cTokens from Compound\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function redeem(\n        address _vaultProxy,\n        bytes calldata,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        // More efficient to parse all from _encodedAssetTransferArgs\n        (\n            ,\n            address[] memory spendAssets,\n            uint256[] memory spendAssetAmounts,\n            address[] memory incomingAssets\n        ) = __decodeEncodedAssetTransferArgs(_encodedAssetTransferArgs);\n\n        ICERC20(spendAssets[0]).redeem(spendAssetAmounts[0]);\n\n        if (incomingAssets[0] == WETH_TOKEN) {\n            IWETH(payable(WETH_TOKEN)).deposit{value: payable(address(this)).balance}();\n        }\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode callArgs for lend and redeem\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address cToken_,\n            uint256 outgoingAssetAmount_,\n            uint256 minIncomingAssetAmount_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (address, uint256, uint256));\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `COMPOUND_PRICE_FEED` variable\n    /// @return compoundPriceFeed_ The `COMPOUND_PRICE_FEED` variable value\n    function getCompoundPriceFeed() external view returns (address compoundPriceFeed_) {\n        return COMPOUND_PRICE_FEED;\n    }\n\n    /// @notice Gets the `WETH_TOKEN` variable\n    /// @return wethToken_ The `WETH_TOKEN` variable value\n    function getWethToken() external view returns (address wethToken_) {\n        return WETH_TOKEN;\n    }\n}\n"
      },
      "contracts/release/interfaces/ICEther.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity ^0.6.12;\n\n/// @title ICEther Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Minimal interface for interactions with Compound Ether\ninterface ICEther {\n    function mint() external payable;\n}\n"
      },
      "contracts/release/interfaces/IChai.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title IChai Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Minimal interface for our interactions with the Chai contract\ninterface IChai is IERC20 {\n    function exit(address, uint256) external;\n\n    function join(address, uint256) external;\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/ChaiAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../../../interfaces/IChai.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title ChaiAdapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for Chai <https://github.com/dapphub/chai>\ncontract ChaiAdapter is AdapterBase {\n    address private immutable CHAI;\n    address private immutable DAI;\n\n    constructor(\n        address _integrationManager,\n        address _chai,\n        address _dai\n    ) public AdapterBase(_integrationManager) {\n        CHAI = _chai;\n        DAI = _dai;\n    }\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ An identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"CHAI\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        if (_selector == LEND_SELECTOR) {\n            (uint256 daiAmount, uint256 minChaiAmount) = __decodeCallArgs(_encodedCallArgs);\n\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = DAI;\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = daiAmount;\n\n            incomingAssets_ = new address[](1);\n            incomingAssets_[0] = CHAI;\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minChaiAmount;\n        } else if (_selector == REDEEM_SELECTOR) {\n            (uint256 chaiAmount, uint256 minDaiAmount) = __decodeCallArgs(_encodedCallArgs);\n\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = CHAI;\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = chaiAmount;\n\n            incomingAssets_ = new address[](1);\n            incomingAssets_[0] = DAI;\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minDaiAmount;\n        } else {\n            revert(\"parseAssetsForMethod: _selector invalid\");\n        }\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Lend Dai for Chai\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function lend(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (uint256 daiAmount, ) = __decodeCallArgs(_encodedCallArgs);\n\n        __approveMaxAsNeeded(DAI, CHAI, daiAmount);\n\n        // Execute Lend on Chai\n        // Chai.join allows specifying the vaultProxy as the destination of Chai tokens\n        IChai(CHAI).join(_vaultProxy, daiAmount);\n    }\n\n    /// @notice Redeem Chai for Dai\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function redeem(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (uint256 chaiAmount, ) = __decodeCallArgs(_encodedCallArgs);\n\n        // Execute redeem on Chai\n        // Chai.exit sends Dai back to the adapter\n        IChai(CHAI).exit(address(this), chaiAmount);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode the encoded call arguments\n    function __decodeCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (uint256 outgoingAmount_, uint256 minIncomingAmount_)\n    {\n        return abi.decode(_encodedCallArgs, (uint256, uint256));\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `CHAI` variable value\n    /// @return chai_ The `CHAI` variable value\n    function getChai() external view returns (address chai_) {\n        return CHAI;\n    }\n\n    /// @notice Gets the `DAI` variable value\n    /// @return dai_ The `DAI` variable value\n    function getDai() external view returns (address dai_) {\n        return DAI;\n    }\n}\n"
      },
      "contracts/mocks/integratees/compound/MockCTokenBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\";\nimport \"../../prices/CentralizedRateProvider.sol\";\nimport \"../../utils/SwapperBase.sol\";\n\ncontract MockCTokenBase is ERC20, SwapperBase, Ownable {\n    address internal immutable TOKEN;\n    address internal immutable CENTRALIZED_RATE_PROVIDER;\n\n    uint256 internal rate;\n\n    mapping(address => mapping(address => uint256)) internal _allowances;\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals,\n        address _token,\n        address _centralizedRateProvider,\n        uint256 _initialRate\n    ) public ERC20(_name, _symbol) {\n        _setupDecimals(_decimals);\n        TOKEN = _token;\n        CENTRALIZED_RATE_PROVIDER = _centralizedRateProvider;\n        rate = _initialRate;\n    }\n\n    function approve(address _spender, uint256 _amount) public virtual override returns (bool) {\n        _allowances[msg.sender][_spender] = _amount;\n        return true;\n    }\n\n    /// @dev Overriden `allowance` function, give the integratee infinite approval by default\n    function allowance(address _owner, address _spender) public view override returns (uint256) {\n        if (_spender == address(this) || _owner == _spender) {\n            return 2**256 - 1;\n        } else {\n            return _allowances[_owner][_spender];\n        }\n    }\n\n    /// @dev Necessary as this contract doesn't directly inherit from MockToken\n    function mintFor(address _who, uint256 _amount) external onlyOwner {\n        _mint(_who, _amount);\n    }\n\n    /// @dev Necessary to allow updates on persistent deployments (e.g Kovan)\n    function setRate(uint256 _rate) public onlyOwner {\n        rate = _rate;\n    }\n\n    function transferFrom(\n        address _sender,\n        address _recipient,\n        uint256 _amount\n    ) public virtual override returns (bool) {\n        _transfer(_sender, _recipient, _amount);\n        return true;\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /// @dev Calculates the cTokenAmount given a tokenAmount\n    /// Makes use of a inverse rate with the CentralizedRateProvider as a derivative can't be used as quoteAsset\n    function __calcCTokenAmount(uint256 _tokenAmount) internal returns (uint256 cTokenAmount_) {\n        uint256 tokenDecimals = ERC20(TOKEN).decimals();\n        uint256 cTokenDecimals = decimals();\n\n        // Result in Token Decimals\n        uint256 tokenPerCTokenUnit = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(address(this), 10**uint256(cTokenDecimals), TOKEN);\n\n        // Result in cToken decimals\n        uint256 inverseRate = uint256(10**tokenDecimals).mul(10**uint256(cTokenDecimals)).div(\n            tokenPerCTokenUnit\n        );\n\n        // Amount in token decimals, result in cToken decimals\n        cTokenAmount_ = _tokenAmount.mul(inverseRate).div(10**tokenDecimals);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @dev Part of ICERC20 token interface\n    function underlying() public view returns (address) {\n        return TOKEN;\n    }\n\n    /// @dev Part of ICERC20 token interface.\n    /// Called from CompoundPriceFeed, returns the actual Rate cToken/Token\n    function exchangeRateStored() public view returns (uint256) {\n        return rate;\n    }\n\n    function getCentralizedRateProvider() public view returns (address) {\n        return CENTRALIZED_RATE_PROVIDER;\n    }\n}\n"
      },
      "contracts/mocks/integratees/compound/MockCTokenIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./MockCTokenBase.sol\";\n\ncontract MockCTokenIntegratee is MockCTokenBase {\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals,\n        address _token,\n        address _centralizedRateProvider,\n        uint256 _initialRate\n    )\n        public\n        MockCTokenBase(_name, _symbol, _decimals, _token, _centralizedRateProvider, _initialRate)\n    {}\n\n    function mint(uint256 _amount) external returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER).calcLiveAssetValue(\n            TOKEN,\n            _amount,\n            address(this)\n        );\n\n        __swapAssets(msg.sender, TOKEN, _amount, address(this), destAmount);\n        return _amount;\n    }\n\n    function redeem(uint256 _amount) external returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER).calcLiveAssetValue(\n            address(this),\n            _amount,\n            TOKEN\n        );\n        __swapAssets(msg.sender, address(this), _amount, TOKEN, destAmount);\n        return _amount;\n    }\n}\n"
      },
      "contracts/mocks/integratees/compound/MockCEtherIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./MockCTokenBase.sol\";\n\ncontract MockCEtherIntegratee is MockCTokenBase {\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals,\n        address _weth,\n        address _centralizedRateProvider,\n        uint256 _initialRate\n    )\n        public\n        MockCTokenBase(_name, _symbol, _decimals, _weth, _centralizedRateProvider, _initialRate)\n    {}\n\n    function mint() external payable {\n        uint256 amount = msg.value;\n        uint256 destAmount = __calcCTokenAmount(amount);\n        __swapAssets(msg.sender, ETH_ADDRESS, amount, address(this), destAmount);\n    }\n\n    function redeem(uint256 _amount) external returns (uint256) {\n        uint256 destAmount = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER).calcLiveAssetValue(\n            address(this),\n            _amount,\n            TOKEN\n        );\n        __swapAssets(msg.sender, address(this), _amount, ETH_ADDRESS, destAmount);\n        return _amount;\n    }\n}\n"
      },
      "contracts/mocks/integratees/MockChaiIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../prices/CentralizedRateProvider.sol\";\nimport \"../tokens/MockToken.sol\";\nimport \"../utils/SwapperBase.sol\";\n\ncontract MockChaiIntegratee is MockToken, SwapperBase {\n    address private immutable CENTRALIZED_RATE_PROVIDER;\n    address public immutable DAI;\n\n    constructor(\n        address _dai,\n        address _centralizedRateProvider,\n        uint8 _decimals\n    ) public MockToken(\"Chai\", \"CHAI\", _decimals) {\n        _setupDecimals(_decimals);\n        CENTRALIZED_RATE_PROVIDER = _centralizedRateProvider;\n        DAI = _dai;\n    }\n\n    function join(address, uint256 _daiAmount) external {\n        uint256 tokenDecimals = ERC20(DAI).decimals();\n        uint256 chaiDecimals = decimals();\n\n        // Calculate the amount of tokens per one unit of DAI\n        uint256 daiPerChaiUnit = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER)\n            .calcLiveAssetValue(address(this), 10**uint256(chaiDecimals), DAI);\n\n        // Calculate the inverse rate to know the amount of CHAI to return from a unit of DAI\n        uint256 inverseRate = uint256(10**tokenDecimals).mul(10**uint256(chaiDecimals)).div(\n            daiPerChaiUnit\n        );\n        // Mint and send those CHAI to sender\n        uint256 destAmount = _daiAmount.mul(inverseRate).div(10**tokenDecimals);\n        _mint(address(this), destAmount);\n        __swapAssets(msg.sender, DAI, _daiAmount, address(this), destAmount);\n    }\n\n    function exit(address payable _trader, uint256 _chaiAmount) external {\n        uint256 destAmount = CentralizedRateProvider(CENTRALIZED_RATE_PROVIDER).calcLiveAssetValue(\n            address(this),\n            _chaiAmount,\n            DAI\n        );\n        // Burn CHAI of the trader.\n        _burn(_trader, _chaiAmount);\n        // Release DAI to the trader.\n        ERC20(DAI).transfer(msg.sender, destAmount);\n    }\n}\n"
      },
      "contracts/release/extensions/integration-manager/integrations/adapters/UniswapV2Adapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/IUniswapV2Factory.sol\";\nimport \"../../../../interfaces/IUniswapV2Router2.sol\";\nimport \"../utils/AdapterBase.sol\";\n\n/// @title UniswapV2Adapter Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Adapter for interacting with Uniswap v2\ncontract UniswapV2Adapter is AdapterBase {\n    using SafeMath for uint256;\n\n    address private immutable FACTORY;\n    address private immutable ROUTER;\n\n    constructor(\n        address _integrationManager,\n        address _router,\n        address _factory\n    ) public AdapterBase(_integrationManager) {\n        FACTORY = _factory;\n        ROUTER = _router;\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Provides a constant string identifier for an adapter\n    /// @return identifier_ The identifer string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"UNISWAP_V2\";\n    }\n\n    /// @notice Parses the expected assets to receive from a call on integration\n    /// @param _selector The function selector for the callOnIntegration\n    /// @param _encodedCallArgs The encoded parameters for the callOnIntegration\n    /// @return spendAssetsHandleType_ A type that dictates how to handle granting\n    /// the adapter access to spend assets (`None` by default)\n    /// @return spendAssets_ The assets to spend in the call\n    /// @return spendAssetAmounts_ The max asset amounts to spend in the call\n    /// @return incomingAssets_ The assets to receive in the call\n    /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call\n    function parseAssetsForMethod(bytes4 _selector, bytes calldata _encodedCallArgs)\n        external\n        view\n        override\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        )\n    {\n        if (_selector == LEND_SELECTOR) {\n            (\n                address[2] memory outgoingAssets,\n                uint256[2] memory maxOutgoingAssetAmounts,\n                ,\n                uint256 minIncomingAssetAmount\n            ) = __decodeLendCallArgs(_encodedCallArgs);\n\n            spendAssets_ = new address[](2);\n            spendAssets_[0] = outgoingAssets[0];\n            spendAssets_[1] = outgoingAssets[1];\n\n            spendAssetAmounts_ = new uint256[](2);\n            spendAssetAmounts_[0] = maxOutgoingAssetAmounts[0];\n            spendAssetAmounts_[1] = maxOutgoingAssetAmounts[1];\n\n            incomingAssets_ = new address[](1);\n            // No need to validate not address(0), this will be caught in IntegrationManager\n            incomingAssets_[0] = IUniswapV2Factory(FACTORY).getPair(\n                outgoingAssets[0],\n                outgoingAssets[1]\n            );\n\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minIncomingAssetAmount;\n        } else if (_selector == REDEEM_SELECTOR) {\n            (\n                uint256 outgoingAssetAmount,\n                address[2] memory incomingAssets,\n                uint256[2] memory minIncomingAssetAmounts\n            ) = __decodeRedeemCallArgs(_encodedCallArgs);\n\n            spendAssets_ = new address[](1);\n            // No need to validate not address(0), this will be caught in IntegrationManager\n            spendAssets_[0] = IUniswapV2Factory(FACTORY).getPair(\n                incomingAssets[0],\n                incomingAssets[1]\n            );\n\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = outgoingAssetAmount;\n\n            incomingAssets_ = new address[](2);\n            incomingAssets_[0] = incomingAssets[0];\n            incomingAssets_[1] = incomingAssets[1];\n\n            minIncomingAssetAmounts_ = new uint256[](2);\n            minIncomingAssetAmounts_[0] = minIncomingAssetAmounts[0];\n            minIncomingAssetAmounts_[1] = minIncomingAssetAmounts[1];\n        } else if (_selector == TAKE_ORDER_SELECTOR) {\n            (\n                address[] memory path,\n                uint256 outgoingAssetAmount,\n                uint256 minIncomingAssetAmount\n            ) = __decodeTakeOrderCallArgs(_encodedCallArgs);\n\n            require(path.length >= 2, \"parseAssetsForMethod: _path must be >= 2\");\n\n            spendAssets_ = new address[](1);\n            spendAssets_[0] = path[0];\n            spendAssetAmounts_ = new uint256[](1);\n            spendAssetAmounts_[0] = outgoingAssetAmount;\n\n            incomingAssets_ = new address[](1);\n            incomingAssets_[0] = path[path.length - 1];\n            minIncomingAssetAmounts_ = new uint256[](1);\n            minIncomingAssetAmounts_[0] = minIncomingAssetAmount;\n        } else {\n            revert(\"parseAssetsForMethod: _selector invalid\");\n        }\n\n        return (\n            IIntegrationManager.SpendAssetsHandleType.Transfer,\n            spendAssets_,\n            spendAssetAmounts_,\n            incomingAssets_,\n            minIncomingAssetAmounts_\n        );\n    }\n\n    /// @notice Lends assets for pool tokens on Uniswap\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function lend(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (\n            address[2] memory outgoingAssets,\n            uint256[2] memory maxOutgoingAssetAmounts,\n            uint256[2] memory minOutgoingAssetAmounts,\n\n        ) = __decodeLendCallArgs(_encodedCallArgs);\n\n        __lend(\n            _vaultProxy,\n            outgoingAssets[0],\n            outgoingAssets[1],\n            maxOutgoingAssetAmounts[0],\n            maxOutgoingAssetAmounts[1],\n            minOutgoingAssetAmounts[0],\n            minOutgoingAssetAmounts[1]\n        );\n    }\n\n    /// @notice Redeems pool tokens on Uniswap\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function redeem(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (\n            uint256 outgoingAssetAmount,\n            address[2] memory incomingAssets,\n            uint256[2] memory minIncomingAssetAmounts\n        ) = __decodeRedeemCallArgs(_encodedCallArgs);\n\n        // More efficient to parse pool token from _encodedAssetTransferArgs than external call\n        (, address[] memory spendAssets, , ) = __decodeEncodedAssetTransferArgs(\n            _encodedAssetTransferArgs\n        );\n\n        __redeem(\n            _vaultProxy,\n            spendAssets[0],\n            outgoingAssetAmount,\n            incomingAssets[0],\n            incomingAssets[1],\n            minIncomingAssetAmounts[0],\n            minIncomingAssetAmounts[1]\n        );\n    }\n\n    /// @notice Trades assets on Uniswap\n    /// @param _vaultProxy The VaultProxy of the calling fund\n    /// @param _encodedCallArgs Encoded order parameters\n    /// @param _encodedAssetTransferArgs Encoded args for expected assets to spend and receive\n    function takeOrder(\n        address _vaultProxy,\n        bytes calldata _encodedCallArgs,\n        bytes calldata _encodedAssetTransferArgs\n    )\n        external\n        onlyIntegrationManager\n        fundAssetsTransferHandler(_vaultProxy, _encodedAssetTransferArgs)\n    {\n        (\n            address[] memory path,\n            uint256 outgoingAssetAmount,\n            uint256 minIncomingAssetAmount\n        ) = __decodeTakeOrderCallArgs(_encodedCallArgs);\n\n        __takeOrder(_vaultProxy, outgoingAssetAmount, minIncomingAssetAmount, path);\n    }\n\n    // PRIVATE FUNCTIONS\n\n    /// @dev Helper to decode the lend encoded call arguments\n    function __decodeLendCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address[2] memory outgoingAssets_,\n            uint256[2] memory maxOutgoingAssetAmounts_,\n            uint256[2] memory minOutgoingAssetAmounts_,\n            uint256 minIncomingAssetAmount_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (address[2], uint256[2], uint256[2], uint256));\n    }\n\n    /// @dev Helper to decode the redeem encoded call arguments\n    function __decodeRedeemCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            uint256 outgoingAssetAmount_,\n            address[2] memory incomingAssets_,\n            uint256[2] memory minIncomingAssetAmounts_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (uint256, address[2], uint256[2]));\n    }\n\n    /// @dev Helper to decode the take order encoded call arguments\n    function __decodeTakeOrderCallArgs(bytes memory _encodedCallArgs)\n        private\n        pure\n        returns (\n            address[] memory path_,\n            uint256 outgoingAssetAmount_,\n            uint256 minIncomingAssetAmount_\n        )\n    {\n        return abi.decode(_encodedCallArgs, (address[], uint256, uint256));\n    }\n\n    /// @dev Helper to execute lend. Avoids stack-too-deep error.\n    function __lend(\n        address _vaultProxy,\n        address _tokenA,\n        address _tokenB,\n        uint256 _amountADesired,\n        uint256 _amountBDesired,\n        uint256 _amountAMin,\n        uint256 _amountBMin\n    ) private {\n        __approveMaxAsNeeded(_tokenA, ROUTER, _amountADesired);\n        __approveMaxAsNeeded(_tokenB, ROUTER, _amountBDesired);\n\n        // Execute lend on Uniswap\n        IUniswapV2Router2(ROUTER).addLiquidity(\n            _tokenA,\n            _tokenB,\n            _amountADesired,\n            _amountBDesired,\n            _amountAMin,\n            _amountBMin,\n            _vaultProxy,\n            block.timestamp.add(1)\n        );\n    }\n\n    /// @dev Helper to execute redeem. Avoids stack-too-deep error.\n    function __redeem(\n        address _vaultProxy,\n        address _poolToken,\n        uint256 _poolTokenAmount,\n        address _tokenA,\n        address _tokenB,\n        uint256 _amountAMin,\n        uint256 _amountBMin\n    ) private {\n        __approveMaxAsNeeded(_poolToken, ROUTER, _poolTokenAmount);\n\n        // Execute redeem on Uniswap\n        IUniswapV2Router2(ROUTER).removeLiquidity(\n            _tokenA,\n            _tokenB,\n            _poolTokenAmount,\n            _amountAMin,\n            _amountBMin,\n            _vaultProxy,\n            block.timestamp.add(1)\n        );\n    }\n\n    /// @dev Helper to execute takeOrder. Avoids stack-too-deep error.\n    function __takeOrder(\n        address _vaultProxy,\n        uint256 _outgoingAssetAmount,\n        uint256 _minIncomingAssetAmount,\n        address[] memory _path\n    ) private {\n        __approveMaxAsNeeded(_path[0], ROUTER, _outgoingAssetAmount);\n\n        // Execute fill\n        IUniswapV2Router2(ROUTER).swapExactTokensForTokens(\n            _outgoingAssetAmount,\n            _minIncomingAssetAmount,\n            _path,\n            _vaultProxy,\n            block.timestamp.add(1)\n        );\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `FACTORY` variable\n    /// @return factory_ The `FACTORY` variable value\n    function getFactory() external view returns (address factory_) {\n        return FACTORY;\n    }\n\n    /// @notice Gets the `ROUTER` variable\n    /// @return router_ The `ROUTER` variable value\n    function getRouter() external view returns (address router_) {\n        return ROUTER;\n    }\n}\n"
      },
      "contracts/release/interfaces/IUniswapV2Router2.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @title UniswapV2Router2 Interface\n/// @author Enzyme Council <security@enzyme.finance>\n/// @dev Minimal interface for our interactions with Uniswap V2's Router2\ninterface IUniswapV2Router2 {\n    function addLiquidity(\n        address,\n        address,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        address,\n        uint256\n    )\n        external\n        returns (\n            uint256,\n            uint256,\n            uint256\n        );\n\n    function removeLiquidity(\n        address,\n        address,\n        uint256,\n        uint256,\n        uint256,\n        address,\n        uint256\n    ) external returns (uint256, uint256);\n\n    function swapExactTokensForTokens(\n        uint256,\n        uint256,\n        address[] calldata,\n        address,\n        uint256\n    ) external returns (uint256[] memory);\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/feeds/ChaiPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../../../../interfaces/IMakerDaoPot.sol\";\nimport \"../IDerivativePriceFeed.sol\";\n\n/// @title ChaiPriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Price source oracle for Chai\ncontract ChaiPriceFeed is IDerivativePriceFeed {\n    using SafeMath for uint256;\n\n    uint256 private constant CHI_DIVISOR = 10**27;\n    address private immutable CHAI;\n    address private immutable DAI;\n    address private immutable DSR_POT;\n\n    constructor(\n        address _chai,\n        address _dai,\n        address _dsrPot\n    ) public {\n        CHAI = _chai;\n        DAI = _dai;\n        DSR_POT = _dsrPot;\n    }\n\n    /// @notice Converts a given amount of a derivative to its underlying asset values\n    /// @param _derivative The derivative to convert\n    /// @param _derivativeAmount The amount of the derivative to convert\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The amount of each underlying asset for the equivalent derivative amount\n    /// @dev Calculation based on Chai source: https://github.com/dapphub/chai/blob/master/src/chai.sol\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        require(isSupportedAsset(_derivative), \"calcUnderlyingValues: Only Chai is supported\");\n\n        underlyings_ = new address[](1);\n        underlyings_[0] = DAI;\n        underlyingAmounts_ = new uint256[](1);\n        underlyingAmounts_[0] = _derivativeAmount.mul(IMakerDaoPot(DSR_POT).chi()).div(\n            CHI_DIVISOR\n        );\n    }\n\n    /// @notice Checks if an asset is supported by the price feed\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is supported\n    function isSupportedAsset(address _asset) public view override returns (bool isSupported_) {\n        return _asset == CHAI;\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `CHAI` variable value\n    /// @return chai_ The `CHAI` variable value\n    function getChai() external view returns (address chai_) {\n        return CHAI;\n    }\n\n    /// @notice Gets the `DAI` variable value\n    /// @return dai_ The `DAI` variable value\n    function getDai() external view returns (address dai_) {\n        return DAI;\n    }\n\n    /// @notice Gets the `DSR_POT` variable value\n    /// @return dsrPot_ The `DSR_POT` variable value\n    function getDsrPot() external view returns (address dsrPot_) {\n        return DSR_POT;\n    }\n}\n"
      },
      "contracts/release/interfaces/IMakerDaoPot.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\n/// @notice Limited interface for Maker DSR's Pot contract\n/// @dev See DSR integration guide: https://github.com/makerdao/developerguides/blob/master/dai/dsr-integration-guide/dsr-integration-guide-01.md\ninterface IMakerDaoPot {\n    function chi() external view returns (uint256);\n\n    function rho() external view returns (uint256);\n\n    function drip() external returns (uint256);\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/utils/EntranceRateFeeBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"./FeeBase.sol\";\n\n/// @title EntranceRateFeeBase Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Calculates a fee based on a rate to be charged to an investor upon entering a fund\nabstract contract EntranceRateFeeBase is FeeBase {\n    using SafeMath for uint256;\n\n    event FundSettingsAdded(address indexed comptrollerProxy, uint256 rate);\n\n    event Settled(address indexed comptrollerProxy, address indexed payer, uint256 sharesQuantity);\n\n    uint256 private constant RATE_DIVISOR = 10**18;\n    IFeeManager.SettlementType private immutable SETTLEMENT_TYPE;\n\n    mapping(address => uint256) private comptrollerProxyToRate;\n\n    constructor(address _feeManager, IFeeManager.SettlementType _settlementType)\n        public\n        FeeBase(_feeManager)\n    {\n        require(\n            _settlementType == IFeeManager.SettlementType.Burn ||\n                _settlementType == IFeeManager.SettlementType.Direct,\n            \"constructor: Invalid _settlementType\"\n        );\n        SETTLEMENT_TYPE = _settlementType;\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /// @notice Add the fee settings for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _settingsData Encoded settings to apply to the policy for a fund\n    function addFundSettings(address _comptrollerProxy, bytes calldata _settingsData)\n        external\n        override\n        onlyFeeManager\n    {\n        uint256 rate = abi.decode(_settingsData, (uint256));\n        require(rate > 0, \"addFundSettings: Fee rate must be >0\");\n\n        comptrollerProxyToRate[_comptrollerProxy] = rate;\n\n        emit FundSettingsAdded(_comptrollerProxy, rate);\n    }\n\n    /// @notice Gets the hooks that are implemented by the fee\n    /// @return implementedHooksForSettle_ The hooks during which settle() is implemented\n    /// @return implementedHooksForUpdate_ The hooks during which update() is implemented\n    /// @return usesGavOnSettle_ True if GAV is used during the settle() implementation\n    /// @return usesGavOnUpdate_ True if GAV is used during the update() implementation\n    /// @dev Used only during fee registration\n    function implementedHooks()\n        external\n        view\n        override\n        returns (\n            IFeeManager.FeeHook[] memory implementedHooksForSettle_,\n            IFeeManager.FeeHook[] memory implementedHooksForUpdate_,\n            bool usesGavOnSettle_,\n            bool usesGavOnUpdate_\n        )\n    {\n        implementedHooksForSettle_ = new IFeeManager.FeeHook[](1);\n        implementedHooksForSettle_[0] = IFeeManager.FeeHook.PostBuyShares;\n\n        return (implementedHooksForSettle_, new IFeeManager.FeeHook[](0), false, false);\n    }\n\n    /// @notice Settles the fee\n    /// @param _comptrollerProxy The ComptrollerProxy of the fund\n    /// @param _settlementData Encoded args to use in calculating the settlement\n    /// @return settlementType_ The type of settlement\n    /// @return payer_ The payer of shares due\n    /// @return sharesDue_ The amount of shares due\n    function settle(\n        address _comptrollerProxy,\n        address,\n        IFeeManager.FeeHook,\n        bytes calldata _settlementData,\n        uint256\n    )\n        external\n        override\n        onlyFeeManager\n        returns (\n            IFeeManager.SettlementType settlementType_,\n            address payer_,\n            uint256 sharesDue_\n        )\n    {\n        uint256 sharesBought;\n        (payer_, , sharesBought) = __decodePostBuySharesSettlementData(_settlementData);\n\n        uint256 rate = comptrollerProxyToRate[_comptrollerProxy];\n        sharesDue_ = sharesBought.mul(rate).div(RATE_DIVISOR.add(rate));\n\n        if (sharesDue_ == 0) {\n            return (IFeeManager.SettlementType.None, address(0), 0);\n        }\n\n        emit Settled(_comptrollerProxy, payer_, sharesDue_);\n\n        return (SETTLEMENT_TYPE, payer_, sharesDue_);\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the `rate` variable for a fund\n    /// @param _comptrollerProxy The ComptrollerProxy contract for the fund\n    /// @return rate_ The `rate` variable value\n    function getRateForFund(address _comptrollerProxy) external view returns (uint256 rate_) {\n        return comptrollerProxyToRate[_comptrollerProxy];\n    }\n\n    /// @notice Gets the `SETTLEMENT_TYPE` variable\n    /// @return settlementType_ The `SETTLEMENT_TYPE` variable value\n    function getSettlementType()\n        external\n        view\n        returns (IFeeManager.SettlementType settlementType_)\n    {\n        return SETTLEMENT_TYPE;\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/EntranceRateDirectFee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./utils/EntranceRateFeeBase.sol\";\n\n/// @title EntranceRateDirectFee Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice An EntranceRateFee that transfers the fee shares to the fund manager\ncontract EntranceRateDirectFee is EntranceRateFeeBase {\n    constructor(address _feeManager)\n        public\n        EntranceRateFeeBase(_feeManager, IFeeManager.SettlementType.Direct)\n    {}\n\n    /// @notice Provides a constant string identifier for a fee\n    /// @return identifier_ The identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ENTRANCE_RATE_DIRECT\";\n    }\n}\n"
      },
      "contracts/release/extensions/fee-manager/fees/EntranceRateBurnFee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"./utils/EntranceRateFeeBase.sol\";\n\n/// @title EntranceRateBurnFee Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice An EntranceRateFee that burns the fee shares\ncontract EntranceRateBurnFee is EntranceRateFeeBase {\n    constructor(address _feeManager)\n        public\n        EntranceRateFeeBase(_feeManager, IFeeManager.SettlementType.Burn)\n    {}\n\n    /// @notice Provides a constant string identifier for a fee\n    /// @return identifier_ The identifier string\n    function identifier() external pure override returns (string memory identifier_) {\n        return \"ENTRANCE_RATE_BURN\";\n    }\n}\n"
      },
      "contracts/mocks/prices/MockChaiPriceSource.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\ncontract MockChaiPriceSource {\n    using SafeMath for uint256;\n\n    uint256 private chiStored = 10**27;\n    uint256 private rhoStored = now;\n\n    function drip() external returns (uint256) {\n        require(now >= rhoStored, \"drip: invalid now\");\n        rhoStored = now;\n        chiStored = chiStored.mul(99).div(100);\n        return chi();\n    }\n\n    ////////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    function chi() public view returns (uint256) {\n        return chiStored;\n    }\n\n    function rho() public view returns (uint256) {\n        return rhoStored;\n    }\n}\n"
      },
      "contracts/mocks/integratees/MockGenericIntegratee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../utils/SwapperBase.sol\";\n\ncontract MockGenericIntegratee is SwapperBase {\n    function swap(\n        address[] calldata _assetsToIntegratee,\n        uint256[] calldata _assetsToIntegrateeAmounts,\n        address[] calldata _assetsFromIntegratee,\n        uint256[] calldata _assetsFromIntegrateeAmounts\n    ) external payable {\n        __swap(\n            msg.sender,\n            _assetsToIntegratee,\n            _assetsToIntegrateeAmounts,\n            _assetsFromIntegratee,\n            _assetsFromIntegrateeAmounts\n        );\n    }\n\n    function swapOnBehalf(\n        address payable _trader,\n        address[] calldata _assetsToIntegratee,\n        uint256[] calldata _assetsToIntegrateeAmounts,\n        address[] calldata _assetsFromIntegratee,\n        uint256[] calldata _assetsFromIntegrateeAmounts\n    ) external payable {\n        __swap(\n            _trader,\n            _assetsToIntegratee,\n            _assetsToIntegrateeAmounts,\n            _assetsFromIntegratee,\n            _assetsFromIntegrateeAmounts\n        );\n    }\n}\n"
      },
      "contracts/release/infrastructure/price-feeds/derivatives/AggregatedDerivativePriceFeed.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n    This file is part of the Enzyme Protocol.\n\n    (c) Enzyme Council <council@enzyme.finance>\n\n    For the full license information, please view the LICENSE\n    file that was distributed with this source code.\n*/\n\npragma solidity 0.6.12;\n\nimport \"../../utils/DispatcherOwnerMixin.sol\";\nimport \"./IAggregatedDerivativePriceFeed.sol\";\n\n/// @title AggregatedDerivativePriceFeed Contract\n/// @author Enzyme Council <security@enzyme.finance>\n/// @notice Aggregates multiple derivative price feeds (e.g., Compound, Chai) and dispatches\n/// rate requests to the appropriate feed\ncontract AggregatedDerivativePriceFeed is IAggregatedDerivativePriceFeed, DispatcherOwnerMixin {\n    event DerivativeAdded(address indexed derivative, address priceFeed);\n\n    event DerivativeRemoved(address indexed derivative);\n\n    event DerivativeUpdated(\n        address indexed derivative,\n        address prevPriceFeed,\n        address nextPriceFeed\n    );\n\n    mapping(address => address) private derivativeToPriceFeed;\n\n    constructor(\n        address _dispatcher,\n        address[] memory _derivatives,\n        address[] memory _priceFeeds\n    ) public DispatcherOwnerMixin(_dispatcher) {\n        if (_derivatives.length > 0) {\n            __addDerivatives(_derivatives, _priceFeeds);\n        }\n    }\n\n    /// @notice Gets the rates for 1 unit of the derivative to its underlying assets\n    /// @param _derivative The derivative for which to get the rates\n    /// @return underlyings_ The underlying assets for the _derivative\n    /// @return underlyingAmounts_ The rates for the _derivative to the underlyings_\n    function calcUnderlyingValues(address _derivative, uint256 _derivativeAmount)\n        external\n        override\n        returns (address[] memory underlyings_, uint256[] memory underlyingAmounts_)\n    {\n        address derivativePriceFeed = derivativeToPriceFeed[_derivative];\n        require(\n            derivativePriceFeed != address(0),\n            \"calcUnderlyingValues: _derivative is not supported\"\n        );\n\n        return\n            IDerivativePriceFeed(derivativePriceFeed).calcUnderlyingValues(\n                _derivative,\n                _derivativeAmount\n            );\n    }\n\n    /// @notice Checks whether an asset is a supported derivative\n    /// @param _asset The asset to check\n    /// @return isSupported_ True if the asset is a supported derivative\n    /// @dev This should be as low-cost and simple as possible\n    function isSupportedAsset(address _asset) external view override returns (bool isSupported_) {\n        return derivativeToPriceFeed[_asset] != address(0);\n    }\n\n    //////////////////////////\n    // DERIVATIVES REGISTRY //\n    //////////////////////////\n\n    /// @notice Adds a list of derivatives with the given price feed values\n    /// @param _derivatives The derivatives to add\n    /// @param _priceFeeds The ordered price feeds corresponding to the list of _derivatives\n    function addDerivatives(address[] calldata _derivatives, address[] calldata _priceFeeds)\n        external\n        onlyDispatcherOwner\n    {\n        require(_derivatives.length > 0, \"addDerivatives: _derivatives cannot be empty\");\n\n        __addDerivatives(_derivatives, _priceFeeds);\n    }\n\n    /// @notice Removes a list of derivatives\n    /// @param _derivatives The derivatives to remove\n    function removeDerivatives(address[] calldata _derivatives) external onlyDispatcherOwner {\n        require(_derivatives.length > 0, \"removeDerivatives: _derivatives cannot be empty\");\n\n        for (uint256 i = 0; i < _derivatives.length; i++) {\n            require(\n                derivativeToPriceFeed[_derivatives[i]] != address(0),\n                \"removeDerivatives: Derivative not yet added\"\n            );\n\n            delete derivativeToPriceFeed[_derivatives[i]];\n\n            emit DerivativeRemoved(_derivatives[i]);\n        }\n    }\n\n    /// @notice Updates a list of derivatives with the given price feed values\n    /// @param _derivatives The derivatives to update\n    /// @param _priceFeeds The ordered price feeds corresponding to the list of _derivatives\n    function updateDerivatives(address[] calldata _derivatives, address[] calldata _priceFeeds)\n        external\n        onlyDispatcherOwner\n    {\n        require(_derivatives.length > 0, \"updateDerivatives: _derivatives cannot be empty\");\n        require(\n            _derivatives.length == _priceFeeds.length,\n            \"updateDerivatives: Unequal _derivatives and _priceFeeds array lengths\"\n        );\n\n        for (uint256 i = 0; i < _derivatives.length; i++) {\n            address prevPriceFeed = derivativeToPriceFeed[_derivatives[i]];\n\n            require(prevPriceFeed != address(0), \"updateDerivatives: Derivative not yet added\");\n            require(_priceFeeds[i] != prevPriceFeed, \"updateDerivatives: Value already set\");\n\n            __validateDerivativePriceFeed(_derivatives[i], _priceFeeds[i]);\n\n            derivativeToPriceFeed[_derivatives[i]] = _priceFeeds[i];\n\n            emit DerivativeUpdated(_derivatives[i], prevPriceFeed, _priceFeeds[i]);\n        }\n    }\n\n    /// @dev Helper to add derivative-feed pairs\n    function __addDerivatives(address[] memory _derivatives, address[] memory _priceFeeds)\n        private\n    {\n        require(\n            _derivatives.length == _priceFeeds.length,\n            \"__addDerivatives: Unequal _derivatives and _priceFeeds array lengths\"\n        );\n\n        for (uint256 i = 0; i < _derivatives.length; i++) {\n            require(\n                derivativeToPriceFeed[_derivatives[i]] == address(0),\n                \"__addDerivatives: Already added\"\n            );\n\n            __validateDerivativePriceFeed(_derivatives[i], _priceFeeds[i]);\n\n            derivativeToPriceFeed[_derivatives[i]] = _priceFeeds[i];\n\n            emit DerivativeAdded(_derivatives[i], _priceFeeds[i]);\n        }\n    }\n\n    /// @dev Helper to validate a derivative price feed\n    function __validateDerivativePriceFeed(address _derivative, address _priceFeed) private view {\n        require(_derivative != address(0), \"__validateDerivativePriceFeed: Empty _derivative\");\n        require(_priceFeed != address(0), \"__validateDerivativePriceFeed: Empty _priceFeed\");\n        require(\n            IDerivativePriceFeed(_priceFeed).isSupportedAsset(_derivative),\n            \"__validateDerivativePriceFeed: Unsupported derivative\"\n        );\n    }\n\n    ///////////////////\n    // STATE GETTERS //\n    ///////////////////\n\n    /// @notice Gets the registered price feed for a given derivative\n    /// @return priceFeed_ The price feed contract address\n    function getPriceFeedForDerivative(address _derivative)\n        external\n        view\n        override\n        returns (address priceFeed_)\n    {\n        return derivativeToPriceFeed[_derivative];\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200,
        "details": {
          "yul": false
        }
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      }
    }
  }}