{"file_path":"./contracts/core/YapeFactory.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {IUniswapV2Pair} from \"../helpers/uni-v2/interfaces/IUniswapV2Pair.sol\";\nimport {UniswapV2Factory} from \"../helpers/uni-v2/UniswapV2Factory.sol\";\nimport {IYapePair} from \"../interfaces/IYapePair.sol\";\nimport {YapePairCode} from \"./YapePairCode.sol\";\n\ncontract YapeFactory is UniswapV2Factory {\n    address public registry;\n    address public operator;\n    address public pairCode;\n\n    constructor(\n        address feeToSetter_,\n        address registry_,\n        address operator_,\n        address pairCode_\n    ) UniswapV2Factory(feeToSetter_) {\n        registry = registry_;\n        operator = operator_;\n        pairCode = pairCode_;\n    }\n\n    function setRegistry(address registry_) external {\n        require(msg.sender == feeToSetter, \"UniswapV2: FORBIDDEN\");\n        registry = registry_;\n    }\n\n    function setOperator(address operator_) external {\n        require(msg.sender == feeToSetter, \"UniswapV2: FORBIDDEN\");\n        operator = operator_;\n    }\n\n    function createPair(address tokenA, address tokenB)\n        external\n        override\n        returns (address pair)\n    {\n        require(tokenA != tokenB, \"Yapeswap: IDENTICAL_ADDRESSES\");\n        (address token0, address token1) = tokenA < tokenB\n            ? (tokenA, tokenB)\n            : (tokenB, tokenA);\n        require(token0 != address(0), \"Yapeswap: ZERO_ADDRESS\");\n        require(getPair[token0][token1] == address(0), \"Yapeswap: PAIR_EXISTS\"); // single check is sufficient\n        bytes memory bytecode = YapePairCode(pairCode).getCreationCode();\n        bytes32 salt = keccak256(abi.encodePacked(token0, token1));\n        assembly {\n            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)\n        }\n        IYapePair(pair).initialize(token0, token1);\n        IYapePair(pair).updateRegistry();\n        getPair[token0][token1] = pair;\n        getPair[token1][token0] = pair; // populate mapping in the reverse direction\n        allPairs.push(pair);\n        emit PairCreated(token0, token1, pair, allPairs.length);\n    }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106100df5760003560e01c80637c64b0f91161008c578063b3ab15fb11610066578063b3ab15fb146101fa578063c9c653961461020d578063e6a4390514610220578063f46901ed1461026157600080fd5b80637c64b0f9146101b2578063a2e74af6146101d2578063a91ee0dc146101e757600080fd5b8063570ca735116100bd578063570ca73514610161578063574f2ba3146101815780637b1039991461019257600080fd5b8063017e7e58146100e4578063094b74151461012e5780631e3dd18b1461014e575b600080fd5b6000546101049073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6001546101049073ffffffffffffffffffffffffffffffffffffffff1681565b61010461015c366004610c3a565b610274565b6005546101049073ffffffffffffffffffffffffffffffffffffffff1681565b600354604051908152602001610125565b6004546101049073ffffffffffffffffffffffffffffffffffffffff1681565b6006546101049073ffffffffffffffffffffffffffffffffffffffff1681565b6101e56101e0366004610af7565b6102ab565b005b6101e56101f5366004610af7565b610378565b6101e5610208366004610af7565b610440565b61010461021b366004610b19565b610508565b61010461022e366004610b19565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b6101e561026f366004610af7565b610a06565b6003818154811061028457600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610331576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e00000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156105a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f59617065737761703a204944454e544943414c5f4144445245535345530000006044820152606401610328565b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106105dd5783856105e0565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff8216610662576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f59617065737761703a205a45524f5f41444452455353000000000000000000006044820152606401610328565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600260209081526040808320858516845290915290205416156106fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f59617065737761703a20504149525f45584953545300000000000000000000006044820152606401610328565b600654604080517ec194db000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169162c194db9160048083019286929190829003018186803b15801561076657600080fd5b505afa15801561077a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107c09190810190610b4c565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086811b8216602084015285901b166034820152909150600090604801604051602081830303815290604052805190602001209050808251602084016000f56040517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015285811660248301529196509086169063485cc95590604401600060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff166349d10b646040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156108f957600080fd5b505af115801561090d573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9095018054909716841790965592548351928352908201527f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9910160405180910390a35050505092915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b803573ffffffffffffffffffffffffffffffffffffffff81168114610af257600080fd5b919050565b600060208284031215610b0957600080fd5b610b1282610ace565b9392505050565b60008060408385031215610b2c57600080fd5b610b3583610ace565b9150610b4360208401610ace565b90509250929050565b60006020808385031215610b5f57600080fd5b825167ffffffffffffffff80821115610b7757600080fd5b818501915085601f830112610b8b57600080fd5b815181811115610b9d57610b9d610c53565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610be357610be3610c53565b816040528281528886848701011115610bfb57600080fd5b600093505b82841015610c1d5784840186015181850187015292850192610c00565b82841115610c2e5760008684830101525b98975050505050505050565b600060208284031215610c4c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220577a4bbed295cf5d009d84c39b2bf0ae14d5dbd706d06636019ea634474e355664736f6c63430008060033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"berlin","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":999999},"remappings":[]},"optimization_runs":999999,"sourcify_repo_url":null,"decoded_constructor_args":[["0xd8965D4fABFa616110Ac8737c74f5e4948C6d952",{"internalType":"address","name":"feeToSetter_","type":"address"}],["0x50c1a2eA0a861A967D9d0FFE2AE4012c2E053804",{"internalType":"address","name":"registry_","type":"address"}],["0xd8965D4fABFa616110Ac8737c74f5e4948C6d952",{"internalType":"address","name":"operator_","type":"address"}],["0x8b2b880303F65Da62ae442A658d5d4170EE470d8",{"internalType":"address","name":"pairCode_","type":"address"}]],"compiler_version":"0.8.6+commit.11564f7e","is_verified_via_verifier_alliance":true,"verified_at":"2025-08-29T16:06:42.631845Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801561001057600080fd5b50604051610db9380380610db983398101604081905261002f9161009e565b600180546001600160a01b039586166001600160a01b03199182161790915560048054948616948216949094179093556005805492851692841692909217909155600680549190931691161790556100f2565b80516001600160a01b038116811461009957600080fd5b919050565b600080600080608085870312156100b457600080fd5b6100bd85610082565b93506100cb60208601610082565b92506100d960408601610082565b91506100e760608601610082565b905092959194509250565b610cb8806101016000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c80637c64b0f91161008c578063b3ab15fb11610066578063b3ab15fb146101fa578063c9c653961461020d578063e6a4390514610220578063f46901ed1461026157600080fd5b80637c64b0f9146101b2578063a2e74af6146101d2578063a91ee0dc146101e757600080fd5b8063570ca735116100bd578063570ca73514610161578063574f2ba3146101815780637b1039991461019257600080fd5b8063017e7e58146100e4578063094b74151461012e5780631e3dd18b1461014e575b600080fd5b6000546101049073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6001546101049073ffffffffffffffffffffffffffffffffffffffff1681565b61010461015c366004610c3a565b610274565b6005546101049073ffffffffffffffffffffffffffffffffffffffff1681565b600354604051908152602001610125565b6004546101049073ffffffffffffffffffffffffffffffffffffffff1681565b6006546101049073ffffffffffffffffffffffffffffffffffffffff1681565b6101e56101e0366004610af7565b6102ab565b005b6101e56101f5366004610af7565b610378565b6101e5610208366004610af7565b610440565b61010461021b366004610b19565b610508565b61010461022e366004610b19565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b6101e561026f366004610af7565b610a06565b6003818154811061028457600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610331576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e00000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156105a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f59617065737761703a204944454e544943414c5f4144445245535345530000006044820152606401610328565b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106105dd5783856105e0565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff8216610662576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f59617065737761703a205a45524f5f41444452455353000000000000000000006044820152606401610328565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600260209081526040808320858516845290915290205416156106fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f59617065737761703a20504149525f45584953545300000000000000000000006044820152606401610328565b600654604080517ec194db000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169162c194db9160048083019286929190829003018186803b15801561076657600080fd5b505afa15801561077a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107c09190810190610b4c565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086811b8216602084015285901b166034820152909150600090604801604051602081830303815290604052805190602001209050808251602084016000f56040517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015285811660248301529196509086169063485cc95590604401600060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff166349d10b646040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156108f957600080fd5b505af115801561090d573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9095018054909716841790965592548351928352908201527f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9910160405180910390a35050505092915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e0000000000000000000000006044820152606401610328565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b803573ffffffffffffffffffffffffffffffffffffffff81168114610af257600080fd5b919050565b600060208284031215610b0957600080fd5b610b1282610ace565b9392505050565b60008060408385031215610b2c57600080fd5b610b3583610ace565b9150610b4360208401610ace565b90509250929050565b60006020808385031215610b5f57600080fd5b825167ffffffffffffffff80821115610b7757600080fd5b818501915085601f830112610b8b57600080fd5b815181811115610b9d57610b9d610c53565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610be357610be3610c53565b816040528281528886848701011115610bfb57600080fd5b600093505b82841015610c1d5784840186015181850187015292850192610c00565b82841115610c2e5760008684830101525b98975050505050505050565b600060208284031215610c4c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea2646970667358221220577a4bbed295cf5d009d84c39b2bf0ae14d5dbd706d06636019ea634474e355664736f6c63430008060033000000000000000000000000d8965d4fabfa616110ac8737c74f5e4948c6d95200000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e053804000000000000000000000000d8965d4fabfa616110ac8737c74f5e4948c6d9520000000000000000000000008b2b880303f65da62ae442a658d5d4170ee470d8","name":"YapeFactory","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"berlin","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"./contracts/core/YapePair.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {SafeMath} from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {UniswapV2Pair} from \"../helpers/uni-v2/UniswapV2Pair.sol\";\nimport {IUniswapV2Factory} from \"../helpers/uni-v2/interfaces/IUniswapV2Factory.sol\";\nimport {UQ112x112} from \"../helpers/uni-v2/libraries/UQ112x112.sol\";\nimport {RegistryAPI} from \"../helpers/yearn/BaseWrapper.sol\";\nimport {YapeWrapper} from \"./YapeWrapper.sol\";\nimport {IYapePair} from \"../interfaces/IYapePair.sol\";\nimport {IYapeFactory} from \"../interfaces/IYapeFactory.sol\";\n\ncontract YapePair is UniswapV2Pair, YapeWrapper {\n    using SafeMath for uint256;\n    using SafeERC20 for IERC20;\n    using UQ112x112 for uint224;\n\n    mapping(address => uint256) public farming;\n\n    uint256 private _minFarming;\n    uint256 private _maxFarming;\n    address private _registry;\n    uint256 private constant DENOMINATOR = 10000;\n\n    event YearnDeposit(address token, uint256 amount);\n    event YearnWithdraw(address token, uint256 amount, uint256 yield);\n\n    modifier onlyOperator() {\n        require(msg.sender == IYapeFactory(factory).operator());\n        _;\n    }\n\n    modifier onlyReserved(address token) {\n        require(\n            token == token0 || token == token1,\n            \"Yapeswap: NOT A RESERVED TOKEN\"\n        );\n        _;\n    }\n\n    modifier keepBalance(address token) {\n        uint256 prevBal = _balanceOf(token);\n        _;\n        require(_balanceOf(token) == prevBal, \"Yapeswap: BALANCE CHANGED\");\n    }\n\n    function mint(address to) public override returns (uint256 liquidity) {\n        liquidity = super.mint(to);\n        _rebalance(token0, 0, false);\n        _rebalance(token1, 0, false);\n    }\n\n    function updateRegistry() public {\n        _registry = IYapeFactory(factory).registry();\n    }\n\n    function setFarmingRatio(uint256 min, uint256 max) external onlyOperator {\n        require(max <= DENOMINATOR);\n        require(min <= max);\n        _minFarming = min;\n        _maxFarming = max;\n    }\n\n    /**\n     * @param token use token0 or token1\n     * @param amount use type(uint256).max (when you want to migrate all)\n     * @param maxMigrationLoss use 0 for the default value\n     */\n    function migrate(\n        address token,\n        uint256 amount,\n        uint256 maxMigrationLoss\n    ) external onlyOperator onlyReserved(token) returns (uint256) {\n        return _migrate(token, address(this), amount, maxMigrationLoss);\n    }\n\n    function rebalance(address token) external onlyReserved(token) {\n        _rebalance(token, 0, true);\n    }\n\n    function registry() public view override returns (RegistryAPI) {\n        return RegistryAPI(_registry);\n    }\n\n    function farmingRatio() public view returns (uint256 min, uint256 max) {\n        return (_minFarming, _maxFarming);\n    }\n\n    function name() public view override returns (string memory) {\n        return \"Yape LP\";\n    }\n\n    function symbol() public view override returns (string memory) {\n        return \"YLP\";\n    }\n\n    function _balanceOf(address token)\n        internal\n        view\n        override\n        returns (uint256)\n    {\n        return IERC20(token).balanceOf(address(this)).add(farming[token]);\n    }\n\n    function _safeTransfer(\n        address token,\n        address to,\n        uint256 value\n    ) internal override {\n        _rebalance(token, value, false);\n        (bool success, bytes memory data) = token.call(\n            abi.encodeWithSelector(SELECTOR, to, value)\n        );\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            \"UniswapV2: TRANSFER_FAILED\"\n        );\n    }\n\n    function _rebalance(\n        address token,\n        uint256 amountOut,\n        bool force\n    ) internal {\n        uint256 newBal = _balanceOf(token).sub(amountOut);\n        uint256 minFarming = newBal.mul(_minFarming).div(DENOMINATOR);\n        uint256 maxFarming = newBal.mul(_maxFarming).div(DENOMINATOR);\n        uint256 currentFarming = farming[token];\n        uint256 avg = Math.average(minFarming, maxFarming);\n        if (currentFarming > maxFarming || (force && currentFarming > avg)) {\n            // should withdraw from Yearn\n            _fromYearn(token, currentFarming - avg);\n        } else if (\n            minFarming > currentFarming || (force && avg > currentFarming)\n        ) {\n            // should deposit to Yearn\n            _toYearn(token, avg - currentFarming);\n        }\n    }\n\n    function _toYearn(address token, uint256 amount)\n        internal\n        keepBalance(token)\n    {\n        uint256 deposited = _deposit(\n            token,\n            address(this),\n            address(this),\n            amount,\n            false\n        );\n        farming[token] = farming[token].add(deposited);\n        emit YearnDeposit(token, amount);\n    }\n\n    function _fromYearn(address token, uint256 amount)\n        internal\n        keepBalance(token)\n    {\n        uint256 yearnBal = totalVaultBalance(token, address(this));\n        uint256 farmingAmount = farming[token];\n        uint256 yield;\n        if (yearnBal > farmingAmount) {\n            yield = yearnBal - farmingAmount;\n        } else {\n            // rare case\n            yield = 0;\n        }\n        uint256 withdrawn = _withdraw(\n            token,\n            address(this),\n            address(this),\n            amount.add(yield),\n            true\n        );\n        uint256 netYield;\n        if (withdrawn > amount) {\n            netYield = withdrawn - amount;\n        } else {\n            netYield = 0;\n        }\n        farming[token] = farmingAmount.sub(withdrawn - netYield);\n        // Send fee\n        address feeTo = IUniswapV2Factory(factory).feeTo();\n        if (netYield > 0) {\n            IERC20(token).safeTransfer(feeTo, netYield);\n        }\n        emit YearnWithdraw(token, withdrawn, netYield);\n    }\n}\n"},{"file_path":"./contracts/core/YapePairCode.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {YapePair} from \"./YapePair.sol\";\n\ncontract YapePairCode {\n    function getCreationCode() public pure returns (bytes memory) {\n        return type(YapePair).creationCode;\n    }\n}\n"},{"file_path":"./contracts/core/YapeWrapper.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {SafeMath} from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport {VaultAPI} from \"../helpers/yearn/BaseStrategy.sol\";\nimport {RegistryAPI} from \"../helpers/yearn/BaseWrapper.sol\";\n\n/**\n * @title Functional Wrapper\n * @author yapeswap\n * @notice\n *  YapeWrapper is a fork of Yearn Finance's BaseWrapper not to store the token address as\n *  the state variable.\n *\n */\nabstract contract YapeWrapper {\n    using SafeERC20 for IERC20;\n    using Math for uint256;\n    using SafeMath for uint256;\n\n    // Reduce number of external calls (SLOADs stay the same)\n    mapping(address => VaultAPI[]) private _cachedVaults;\n\n    // ERC20 Unlimited Approvals (short-circuits VaultAPI.transferFrom)\n    uint256 constant UNLIMITED_APPROVAL = type(uint256).max;\n    // Sentinal values used to save gas on deposit/withdraw/migrate\n    // NOTE: DEPOSIT_EVERYTHING == WITHDRAW_EVERYTHING == MIGRATE_EVERYTHING\n    uint256 constant DEPOSIT_EVERYTHING = type(uint256).max;\n    uint256 constant WITHDRAW_EVERYTHING = type(uint256).max;\n    uint256 constant MIGRATE_EVERYTHING = type(uint256).max;\n    // VaultsAPI.depositLimit is unlimited\n    uint256 constant UNCAPPED_DEPOSITS = type(uint256).max;\n\n    /**\n     * @notice\n     *  Used to get the most revent vault for the token using the registry.\n     * @return An instance of a VaultAPI\n     */\n    function bestVault(address token) public view virtual returns (VaultAPI) {\n        return VaultAPI(registry().latestVault(token));\n    }\n\n    /**\n     * @notice\n     *  Used to get all vaults from the registery for the token\n     * @return An array containing instances of VaultAPI\n     */\n    function allVaults(address token)\n        public\n        view\n        virtual\n        returns (VaultAPI[] memory)\n    {\n        uint256 cache_length = _cachedVaults[token].length;\n        uint256 num_vaults = registry().numVaults(token);\n\n        // Use cached\n        if (cache_length == num_vaults) {\n            return _cachedVaults[token];\n        }\n\n        VaultAPI[] memory vaults = new VaultAPI[](num_vaults);\n\n        for (uint256 vault_id = 0; vault_id < cache_length; vault_id++) {\n            vaults[vault_id] = _cachedVaults[token][vault_id];\n        }\n\n        for (\n            uint256 vault_id = cache_length;\n            vault_id < num_vaults;\n            vault_id++\n        ) {\n            vaults[vault_id] = VaultAPI(registry().vaults(token, vault_id));\n        }\n\n        return vaults;\n    }\n\n    function _updateVaultCache(address token, VaultAPI[] memory vaults)\n        internal\n    {\n        // NOTE: even though `registry` is update-able by Yearn, the intended behavior\n        //       is that any future upgrades to the registry will replay the version\n        //       history so that this cached value does not get out of date.\n        if (vaults.length > _cachedVaults[token].length) {\n            _cachedVaults[token] = vaults;\n        }\n    }\n\n    /**\n     * @notice\n     *  Used to get the balance of an account accross all the vaults for a token.\n     *  @dev will be used to get the wrapper balance using totalVaultBalance(address(this)).\n     *  @param account The address of the account.\n     *  @return balance of token for the account accross all the vaults.\n     */\n    function totalVaultBalance(address token, address account)\n        public\n        view\n        returns (uint256 balance)\n    {\n        VaultAPI[] memory vaults = allVaults(token);\n\n        for (uint256 id = 0; id < vaults.length; id++) {\n            balance = balance.add(\n                vaults[id]\n                .balanceOf(account)\n                .mul(vaults[id].pricePerShare())\n                .div(10**uint256(vaults[id].decimals()))\n            );\n        }\n    }\n\n    /**\n     * @notice\n     *  Used to get the TVL on the underlying vaults.\n     *  @return assets the sum of all the assets managed by the underlying vaults.\n     */\n    function totalAssets(address token) public view returns (uint256 assets) {\n        VaultAPI[] memory vaults = allVaults(token);\n\n        for (uint256 id = 0; id < vaults.length; id++) {\n            assets = assets.add(vaults[id].totalAssets());\n        }\n    }\n\n    function _deposit(\n        address token,\n        address depositor,\n        address receiver,\n        uint256 amount, // if `MAX_UINT256`, just deposit everything\n        bool pullFunds // If true, funds need to be pulled from `depositor` via `transferFrom`\n    ) internal returns (uint256 deposited) {\n        VaultAPI _bestVault = bestVault(token);\n        // in case there does not exist yearn vault\n        if (address(_bestVault) == address(0)) return 0;\n\n        IERC20 _token = IERC20(token);\n\n        if (pullFunds) {\n            if (amount != DEPOSIT_EVERYTHING) {\n                _token.safeTransferFrom(depositor, address(this), amount);\n            } else {\n                _token.safeTransferFrom(\n                    depositor,\n                    address(this),\n                    _token.balanceOf(depositor)\n                );\n            }\n        }\n\n        if (_token.allowance(address(this), address(_bestVault)) < amount) {\n            _token.safeApprove(address(_bestVault), 0); // Avoid issues with some tokens requiring 0\n            _token.safeApprove(address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted\n        }\n\n        // Depositing returns number of shares deposited\n        // NOTE: Shortcut here is assuming the number of tokens deposited is equal to the\n        //       number of shares credited, which helps avoid an occasional multiplication\n        //       overflow if trying to adjust the number of shares by the share price.\n        uint256 beforeBal = _token.balanceOf(address(this));\n        if (receiver != address(this)) {\n            _bestVault.deposit(amount, receiver);\n        } else if (amount != DEPOSIT_EVERYTHING) {\n            _bestVault.deposit(amount);\n        } else {\n            _bestVault.deposit();\n        }\n\n        uint256 afterBal = _token.balanceOf(address(this));\n        deposited = beforeBal.sub(afterBal);\n        // `receiver` now has shares of `_bestVault` as balance, converted to `token` here\n        // Issue a refund if not everything was deposited\n        if (depositor != address(this) && afterBal > 0)\n            _token.safeTransfer(depositor, afterBal);\n    }\n\n    function _withdraw(\n        address token,\n        address sender,\n        address receiver,\n        uint256 amount, // if `MAX_UINT256`, just withdraw everything\n        bool withdrawFromBest // If true, also withdraw from `_bestVault`\n    ) internal returns (uint256 withdrawn) {\n        VaultAPI _bestVault = bestVault(token);\n        IERC20 _token = IERC20(token);\n\n        VaultAPI[] memory vaults = allVaults(token);\n        _updateVaultCache(address(token), vaults);\n\n        // NOTE: This loop will attempt to withdraw from each Vault in `allVaults` that `sender`\n        //       is deposited in, up to `amount` tokens. The withdraw action can be expensive,\n        //       so it if there is a denial of service issue in withdrawing, the downstream usage\n        //       of this wrapper contract must give an alternative method of withdrawing using\n        //       this function so that `amount` is less than the full amount requested to withdraw\n        //       (e.g. \"piece-wise withdrawals\"), leading to less loop iterations such that the\n        //       DoS issue is mitigated (at a tradeoff of requiring more txns from the end user).\n        for (uint256 id = 0; id < vaults.length; id++) {\n            if (!withdrawFromBest && vaults[id] == _bestVault) {\n                continue; // Don't withdraw from the best\n            }\n\n            // Start with the total shares that `sender` has\n            uint256 availableShares = vaults[id].balanceOf(sender);\n\n            // Restrict by the allowance that `sender` has to this contract\n            // NOTE: No need for allowance check if `sender` is this contract\n            if (sender != address(this)) {\n                availableShares = Math.min(\n                    availableShares,\n                    vaults[id].allowance(sender, address(this))\n                );\n            }\n\n            // Limit by maximum withdrawal size from each vault\n            availableShares = Math.min(\n                availableShares,\n                vaults[id].maxAvailableShares()\n            );\n\n            if (availableShares > 0) {\n                // Intermediate step to move shares to this contract before withdrawing\n                // NOTE: No need for share transfer if this contract is `sender`\n                if (sender != address(this))\n                    vaults[id].transferFrom(\n                        sender,\n                        address(this),\n                        availableShares\n                    );\n\n                if (amount != WITHDRAW_EVERYTHING) {\n                    // Compute amount to withdraw fully to satisfy the request\n                    uint256 estimatedShares = amount\n                    .sub(withdrawn) // NOTE: Changes every iteration\n                    .mul(10**uint256(vaults[id].decimals()))\n                    .div(vaults[id].pricePerShare()); // NOTE: Every Vault is different\n\n                    // Limit amount to withdraw to the maximum made available to this contract\n                    // NOTE: Avoid corner case where `estimatedShares` isn't precise enough\n                    // NOTE: If `0 < estimatedShares < 1` but `availableShares > 1`, this will withdraw more than necessary\n                    if (\n                        estimatedShares > 0 && estimatedShares < availableShares\n                    ) {\n                        withdrawn = withdrawn.add(\n                            vaults[id].withdraw(estimatedShares)\n                        );\n                    } else {\n                        withdrawn = withdrawn.add(\n                            vaults[id].withdraw(availableShares)\n                        );\n                    }\n                } else {\n                    withdrawn = withdrawn.add(vaults[id].withdraw());\n                }\n\n                // Check if we have fully satisfied the request\n                // NOTE: use `amount = WITHDRAW_EVERYTHING` for withdrawing everything\n                if (amount <= withdrawn) break; // withdrawn as much as we needed\n            }\n        }\n\n        // If we have extra, deposit back into `_bestVault` for `sender`\n        // NOTE: Invariant is `withdrawn <= amount`\n        if (\n            withdrawn > amount &&\n            withdrawn.sub(amount) >\n            _bestVault.pricePerShare().div(10**_bestVault.decimals())\n        ) {\n            // Don't forget to approve the deposit\n            if (\n                _token.allowance(address(this), address(_bestVault)) <\n                withdrawn.sub(amount)\n            ) {\n                _token.safeApprove(address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted\n            }\n\n            _bestVault.deposit(withdrawn.sub(amount), sender);\n            withdrawn = amount;\n        }\n\n        // `receiver` now has `withdrawn` tokens as balance\n        if (receiver != address(this)) _token.safeTransfer(receiver, withdrawn);\n    }\n\n    function _migrate(\n        address token,\n        address account,\n        uint256 amount,\n        uint256 maxMigrationLoss\n    ) internal returns (uint256 migrated) {\n        VaultAPI _bestVault = bestVault(address(token));\n\n        // NOTE: Only override if we aren't migrating everything\n        uint256 _depositLimit = _bestVault.depositLimit();\n        uint256 _totalAssets = _bestVault.totalAssets();\n        if (_depositLimit <= _totalAssets) return 0; // Nothing to migrate (not a failure)\n\n        uint256 _amount = amount;\n        if (\n            _depositLimit < UNCAPPED_DEPOSITS && _amount < WITHDRAW_EVERYTHING\n        ) {\n            // Can only deposit up to this amount\n            uint256 _depositLeft = _depositLimit.sub(_totalAssets);\n            if (_amount > _depositLeft) _amount = _depositLeft;\n        }\n\n        if (_amount > 0) {\n            // NOTE: `false` = don't withdraw from `_bestVault`\n            uint256 withdrawn = _withdraw(\n                token,\n                account,\n                address(this),\n                _amount,\n                false\n            );\n            if (withdrawn == 0) return 0; // Nothing to migrate (not a failure)\n\n            // NOTE: `false` = don't do `transferFrom` because it's already local\n            migrated = _deposit(\n                token,\n                address(this),\n                account,\n                withdrawn,\n                false\n            );\n            // NOTE: Due to the precision loss of certain calculations, there is a small inefficency\n            //       on how migrations are calculated, and this could lead to a DoS issue. Hence, this\n            //       value is made to be configurable to allow the user to specify how much is acceptable\n            require(withdrawn.sub(migrated) <= maxMigrationLoss);\n        } // else: nothing to migrate! (not a failure)\n    }\n\n    function registry() public view virtual returns (RegistryAPI);\n}\n"},{"file_path":"./contracts/helpers/uni-v2/UniswapV2ERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\nimport \"./interfaces/IUniswapV2ERC20.sol\";\nimport \"./libraries/SafeMath.sol\";\n\ncontract UniswapV2ERC20 {\n    using SafeMath for uint256;\n\n    uint8 public constant decimals = 18;\n\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    bytes32 public DOMAIN_SEPARATOR;\n    // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    bytes32 public constant PERMIT_TYPEHASH =\n        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n    mapping(address => uint256) public nonces;\n\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    constructor() {\n        uint256 chainId;\n        assembly {\n            chainId := chainid()\n        }\n        DOMAIN_SEPARATOR = keccak256(\n            abi.encode(\n                keccak256(\n                    \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n                ),\n                keccak256(bytes(name())),\n                keccak256(bytes(\"1\")),\n                chainId,\n                address(this)\n            )\n        );\n    }\n\n    function _mint(address to, uint256 value) internal {\n        totalSupply = totalSupply.add(value);\n        balanceOf[to] = balanceOf[to].add(value);\n        emit Transfer(address(0), to, value);\n    }\n\n    function _burn(address from, uint256 value) internal {\n        balanceOf[from] = balanceOf[from].sub(value);\n        totalSupply = totalSupply.sub(value);\n        emit Transfer(from, address(0), value);\n    }\n\n    function _approve(\n        address owner,\n        address spender,\n        uint256 value\n    ) private {\n        allowance[owner][spender] = value;\n        emit Approval(owner, spender, value);\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 value\n    ) private {\n        balanceOf[from] = balanceOf[from].sub(value);\n        balanceOf[to] = balanceOf[to].add(value);\n        emit Transfer(from, to, value);\n    }\n\n    function approve(address spender, uint256 value) external returns (bool) {\n        _approve(msg.sender, spender, value);\n        return true;\n    }\n\n    function transfer(address to, uint256 value) external returns (bool) {\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool) {\n        if (allowance[from][msg.sender] != ~uint256(0)) {\n            allowance[from][msg.sender] = allowance[from][msg.sender].sub(\n                value\n            );\n        }\n        _transfer(from, to, value);\n        return true;\n    }\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        require(deadline >= block.timestamp, \"UniswapV2: EXPIRED\");\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                \"\\x19\\x01\",\n                DOMAIN_SEPARATOR,\n                keccak256(\n                    abi.encode(\n                        PERMIT_TYPEHASH,\n                        owner,\n                        spender,\n                        value,\n                        nonces[owner]++,\n                        deadline\n                    )\n                )\n            )\n        );\n        address recoveredAddress = ecrecover(digest, v, r, s);\n        require(\n            recoveredAddress != address(0) && recoveredAddress == owner,\n            \"UniswapV2: INVALID_SIGNATURE\"\n        );\n        _approve(owner, spender, value);\n    }\n\n    function name() public view virtual returns (string memory) {\n        return \"Uniswap V2\";\n    }\n\n    function symbol() public view virtual returns (string memory) {\n        return \"UNI-V2\";\n    }\n}\n"},{"file_path":"./contracts/helpers/uni-v2/UniswapV2Factory.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\nimport \"./interfaces/IUniswapV2Factory.sol\";\nimport \"./UniswapV2Pair.sol\";\n\ncontract UniswapV2Factory {\n    address public feeTo;\n    address public feeToSetter;\n\n    mapping(address => mapping(address => address)) public getPair;\n    address[] public allPairs;\n\n    event PairCreated(\n        address indexed token0,\n        address indexed token1,\n        address pair,\n        uint256\n    );\n\n    constructor(address _feeToSetter) {\n        feeToSetter = _feeToSetter;\n    }\n\n    function allPairsLength() external view returns (uint256) {\n        return allPairs.length;\n    }\n\n    function createPair(address tokenA, address tokenB)\n        external\n        virtual\n        returns (address pair)\n    {\n        require(tokenA != tokenB, \"UniswapV2: IDENTICAL_ADDRESSES\");\n        (address token0, address token1) = tokenA < tokenB\n            ? (tokenA, tokenB)\n            : (tokenB, tokenA);\n        require(token0 != address(0), \"UniswapV2: ZERO_ADDRESS\");\n        require(\n            getPair[token0][token1] == address(0),\n            \"UniswapV2: PAIR_EXISTS\"\n        ); // single check is sufficient\n        bytes memory bytecode = type(UniswapV2Pair).creationCode;\n        bytes32 salt = keccak256(abi.encodePacked(token0, token1));\n        assembly {\n            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)\n        }\n        IUniswapV2Pair(pair).initialize(token0, token1);\n        getPair[token0][token1] = pair;\n        getPair[token1][token0] = pair; // populate mapping in the reverse direction\n        allPairs.push(pair);\n        emit PairCreated(token0, token1, pair, allPairs.length);\n    }\n\n    function setFeeTo(address _feeTo) external {\n        require(msg.sender == feeToSetter, \"UniswapV2: FORBIDDEN\");\n        feeTo = _feeTo;\n    }\n\n    function setFeeToSetter(address _feeToSetter) external {\n        require(msg.sender == feeToSetter, \"UniswapV2: FORBIDDEN\");\n        feeToSetter = _feeToSetter;\n    }\n}\n"},{"file_path":"./contracts/helpers/uni-v2/UniswapV2Pair.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\nimport \"./interfaces/IUniswapV2Pair.sol\";\nimport \"./UniswapV2ERC20.sol\";\nimport \"./libraries/Math.sol\";\nimport \"./libraries/UQ112x112.sol\";\nimport \"./interfaces/IERC20.sol\";\nimport \"./interfaces/IUniswapV2Factory.sol\";\nimport \"./interfaces/IUniswapV2Callee.sol\";\n\ncontract UniswapV2Pair is UniswapV2ERC20 {\n    using SafeMath for uint256;\n    using UQ112x112 for uint224;\n\n    uint256 public constant MINIMUM_LIQUIDITY = 10**3;\n    bytes4 internal constant SELECTOR =\n        bytes4(keccak256(bytes(\"transfer(address,uint256)\")));\n\n    address public factory;\n    address public token0;\n    address public token1;\n\n    uint112 internal reserve0; // uses single storage slot, accessible via getReserves\n    uint112 internal reserve1; // uses single storage slot, accessible via getReserves\n    uint32 internal blockTimestampLast; // uses single storage slot, accessible via getReserves\n\n    uint256 public price0CumulativeLast;\n    uint256 public price1CumulativeLast;\n    uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event\n\n    uint256 internal unlocked = 1;\n    modifier lock() {\n        require(unlocked == 1, \"UniswapV2: LOCKED\");\n        unlocked = 0;\n        _;\n        unlocked = 1;\n    }\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n    event Burn(\n        address indexed sender,\n        uint256 amount0,\n        uint256 amount1,\n        address indexed to\n    );\n    event Swap(\n        address indexed sender,\n        uint256 amount0In,\n        uint256 amount1In,\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    constructor() {\n        factory = msg.sender;\n    }\n\n    // called once by the factory at time of deployment\n    function initialize(address _token0, address _token1) public virtual {\n        require(msg.sender == factory, \"UniswapV2: FORBIDDEN\"); // sufficient check\n        token0 = _token0;\n        token1 = _token1;\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function mint(address to) public virtual lock returns (uint256 liquidity) {\n        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings\n        uint256 balance0 = _balanceOf(token0);\n        uint256 balance1 = _balanceOf(token1);\n        uint256 amount0 = balance0.sub(_reserve0);\n        uint256 amount1 = balance1.sub(_reserve1);\n\n        bool feeOn = _mintFee(_reserve0, _reserve1);\n        uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee\n        if (_totalSupply == 0) {\n            liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);\n            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens\n        } else {\n            liquidity = Math.min(\n                amount0.mul(_totalSupply) / _reserve0,\n                amount1.mul(_totalSupply) / _reserve1\n            );\n        }\n        require(liquidity > 0, \"UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED\");\n        _mint(to, liquidity);\n\n        _update(balance0, balance1, _reserve0, _reserve1);\n        if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date\n        emit Mint(msg.sender, amount0, amount1);\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function burn(address to)\n        public\n        virtual\n        lock\n        returns (uint256 amount0, uint256 amount1)\n    {\n        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings\n        address _token0 = token0; // gas savings\n        address _token1 = token1; // gas savings\n        uint256 balance0 = _balanceOf(_token0);\n        uint256 balance1 = _balanceOf(_token1);\n        uint256 liquidity = balanceOf[address(this)];\n\n        bool feeOn = _mintFee(_reserve0, _reserve1);\n        uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee\n        amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution\n        amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution\n        require(\n            amount0 > 0 && amount1 > 0,\n            \"UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED\"\n        );\n        _burn(address(this), liquidity);\n        _safeTransfer(_token0, to, amount0);\n        _safeTransfer(_token1, to, amount1);\n        balance0 = _balanceOf(_token0);\n        balance1 = _balanceOf(_token1);\n\n        _update(balance0, balance1, _reserve0, _reserve1);\n        if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date\n        emit Burn(msg.sender, amount0, amount1, to);\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function swap(\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address to,\n        bytes calldata data\n    ) public virtual lock {\n        require(\n            amount0Out > 0 || amount1Out > 0,\n            \"UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT\"\n        );\n        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings\n        require(\n            amount0Out < _reserve0 && amount1Out < _reserve1,\n            \"UniswapV2: INSUFFICIENT_LIQUIDITY\"\n        );\n\n        uint256 balance0;\n        uint256 balance1;\n        {\n            // scope for _token{0,1}, avoids stack too deep errors\n            address _token0 = token0;\n            address _token1 = token1;\n            require(to != _token0 && to != _token1, \"UniswapV2: INVALID_TO\");\n            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens\n            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens\n            if (data.length > 0)\n                IUniswapV2Callee(to).uniswapV2Call(\n                    msg.sender,\n                    amount0Out,\n                    amount1Out,\n                    data\n                );\n            balance0 = _balanceOf(_token0);\n            balance1 = _balanceOf(_token1);\n        }\n        uint256 amount0In = balance0 > _reserve0 - amount0Out\n            ? balance0 - (_reserve0 - amount0Out)\n            : 0;\n        uint256 amount1In = balance1 > _reserve1 - amount1Out\n            ? balance1 - (_reserve1 - amount1Out)\n            : 0;\n        require(\n            amount0In > 0 || amount1In > 0,\n            \"UniswapV2: INSUFFICIENT_INPUT_AMOUNT\"\n        );\n        {\n            // scope for reserve{0,1}Adjusted, avoids stack too deep errors\n            uint256 balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));\n            uint256 balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));\n            require(\n                balance0Adjusted.mul(balance1Adjusted) >=\n                    uint256(_reserve0).mul(_reserve1).mul(1000**2),\n                \"UniswapV2: K\"\n            );\n        }\n\n        _update(balance0, balance1, _reserve0, _reserve1);\n        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);\n    }\n\n    // force balances to match reserves\n    function skim(address to) public virtual lock {\n        address _token0 = token0; // gas savings\n        address _token1 = token1; // gas savings\n        _safeTransfer(_token0, to, _balanceOf(_token0).sub(reserve0));\n        _safeTransfer(_token1, to, _balanceOf(_token1).sub(reserve1));\n    }\n\n    // force reserves to match balances\n    function sync() public virtual lock {\n        _update(_balanceOf(token0), _balanceOf(token1), reserve0, reserve1);\n    }\n\n    function getReserves()\n        public\n        view\n        returns (\n            uint112 _reserve0,\n            uint112 _reserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n        _blockTimestampLast = blockTimestampLast;\n    }\n\n    function _safeTransfer(\n        address token,\n        address to,\n        uint256 value\n    ) internal virtual {\n        (bool success, bytes memory data) = token.call(\n            abi.encodeWithSelector(SELECTOR, to, value)\n        );\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            \"UniswapV2: TRANSFER_FAILED\"\n        );\n    }\n\n    // update reserves and, on the first call per block, price accumulators\n    function _update(\n        uint256 balance0,\n        uint256 balance1,\n        uint112 _reserve0,\n        uint112 _reserve1\n    ) internal virtual {\n        require(\n            balance0 <= ~uint112(0) && balance1 <= ~uint112(0),\n            \"UniswapV2: OVERFLOW\"\n        );\n        uint32 blockTimestamp = uint32(block.timestamp % 2**32);\n        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired\n        if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {\n            // * never overflows, and + overflow is desired\n            price0CumulativeLast +=\n                uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) *\n                timeElapsed;\n            price1CumulativeLast +=\n                uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) *\n                timeElapsed;\n        }\n        reserve0 = uint112(balance0);\n        reserve1 = uint112(balance1);\n        blockTimestampLast = blockTimestamp;\n        emit Sync(reserve0, reserve1);\n    }\n\n    // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)\n    function _mintFee(uint112 _reserve0, uint112 _reserve1)\n        internal\n        virtual\n        returns (bool feeOn)\n    {\n        address feeTo = IUniswapV2Factory(factory).feeTo();\n        feeOn = feeTo != address(0);\n        uint256 _kLast = kLast; // gas savings\n        if (feeOn) {\n            if (_kLast != 0) {\n                uint256 rootK = Math.sqrt(uint256(_reserve0).mul(_reserve1));\n                uint256 rootKLast = Math.sqrt(_kLast);\n                if (rootK > rootKLast) {\n                    uint256 numerator = totalSupply.mul(rootK.sub(rootKLast));\n                    uint256 denominator = rootK.mul(5).add(rootKLast);\n                    uint256 liquidity = numerator / denominator;\n                    if (liquidity > 0) _mint(feeTo, liquidity);\n                }\n            }\n        } else if (_kLast != 0) {\n            kLast = 0;\n        }\n    }\n\n    function _balanceOf(address token) internal view virtual returns (uint256) {\n        return IERC20(token).balanceOf(address(this));\n    }\n}\n"},{"file_path":"./contracts/helpers/uni-v2/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\ninterface IERC20 {\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender)\n        external\n        view\n        returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n}\n"},{"file_path":"./contracts/helpers/uni-v2/interfaces/IUniswapV2Callee.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\ninterface IUniswapV2Callee {\n    function uniswapV2Call(\n        address sender,\n        uint256 amount0,\n        uint256 amount1,\n        bytes calldata data\n    ) external;\n}\n"},{"file_path":"./contracts/helpers/uni-v2/interfaces/IUniswapV2ERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\ninterface IUniswapV2ERC20 {\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external pure returns (string memory);\n\n    function symbol() external pure returns (string memory);\n\n    function decimals() external pure returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender)\n        external\n        view\n        returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n    function nonces(address owner) external view returns (uint256);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n}\n"},{"file_path":"./contracts/helpers/uni-v2/interfaces/IUniswapV2Factory.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\ninterface IUniswapV2Factory {\n    event PairCreated(\n        address indexed token0,\n        address indexed token1,\n        address pair,\n        uint256\n    );\n\n    function feeTo() external view returns (address);\n\n    function feeToSetter() external view returns (address);\n\n    function getPair(address tokenA, address tokenB)\n        external\n        view\n        returns (address pair);\n\n    function allPairs(uint256) external view returns (address pair);\n\n    function allPairsLength() external view returns (uint256);\n\n    function createPair(address tokenA, address tokenB)\n        external\n        returns (address pair);\n\n    function setFeeTo(address) external;\n\n    function setFeeToSetter(address) external;\n}\n"},{"file_path":"./contracts/helpers/uni-v2/interfaces/IUniswapV2Pair.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\ninterface IUniswapV2Pair {\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external pure returns (string memory);\n\n    function symbol() external pure returns (string memory);\n\n    function decimals() external pure returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender)\n        external\n        view\n        returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n    function nonces(address owner) external view returns (uint256);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n    event Burn(\n        address indexed sender,\n        uint256 amount0,\n        uint256 amount1,\n        address indexed to\n    );\n    event Swap(\n        address indexed sender,\n        uint256 amount0In,\n        uint256 amount1In,\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint256);\n\n    function factory() external view returns (address);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function getReserves()\n        external\n        view\n        returns (\n            uint112 reserve0,\n            uint112 reserve1,\n            uint32 blockTimestampLast\n        );\n\n    function price0CumulativeLast() external view returns (uint256);\n\n    function price1CumulativeLast() external view returns (uint256);\n\n    function kLast() external view returns (uint256);\n\n    function mint(address to) external returns (uint256 liquidity);\n\n    function burn(address to)\n        external\n        returns (uint256 amount0, uint256 amount1);\n\n    function swap(\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address to,\n        bytes calldata data\n    ) external;\n\n    function skim(address to) external;\n\n    function sync() external;\n\n    function initialize(address, address) external;\n}\n"},{"file_path":"./contracts/helpers/uni-v2/libraries/Math.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\n// a library for performing various math operations\n\nlibrary Math {\n    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = x < y ? x : y;\n    }\n\n    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)\n    function sqrt(uint256 y) internal 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    }\n}\n"},{"file_path":"./contracts/helpers/uni-v2/libraries/SafeMath.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\n// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)\n\nlibrary SafeMath {\n    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require((z = x + y) >= x, \"ds-math-add-overflow\");\n    }\n\n    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require((z = x - y) <= x, \"ds-math-sub-underflow\");\n    }\n\n    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require(y == 0 || (z = x * y) / y == x, \"ds-math-mul-overflow\");\n    }\n}\n"},{"file_path":"./contracts/helpers/uni-v2/libraries/UQ112x112.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\n\n// range: [0, 2**112 - 1]\n// resolution: 1 / 2**112\n\nlibrary UQ112x112 {\n    uint224 constant Q112 = 2**112;\n\n    // encode a uint112 as a UQ112x112\n    function encode(uint112 y) internal pure returns (uint224 z) {\n        z = uint224(y) * Q112; // never overflows\n    }\n\n    // divide a UQ112x112 by a uint112, returning a UQ112x112\n    function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {\n        z = x / uint224(y);\n    }\n}\n"},{"file_path":"./contracts/helpers/yearn/BaseStrategy.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {SafeMath} from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nstruct StrategyParams {\n    uint256 performanceFee;\n    uint256 activation;\n    uint256 debtRatio;\n    uint256 minDebtPerHarvest;\n    uint256 maxDebtPerHarvest;\n    uint256 lastReport;\n    uint256 totalDebt;\n    uint256 totalGain;\n    uint256 totalLoss;\n    bool enforceChangeLimit;\n    uint256 profitLimitRatio;\n    uint256 lossLimitRatio;\n    address customCheck;\n}\n\ninterface VaultAPI is IERC20 {\n    function name() external view returns (string calldata);\n\n    function symbol() external view returns (string calldata);\n\n    function decimals() external view returns (uint256);\n\n    function apiVersion() external pure returns (string memory);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 expiry,\n        bytes calldata signature\n    ) external returns (bool);\n\n    // NOTE: Vyper produces multiple signatures for a given function with \"default\" args\n    function deposit() external returns (uint256);\n\n    function deposit(uint256 amount) external returns (uint256);\n\n    function deposit(uint256 amount, address recipient)\n        external\n        returns (uint256);\n\n    // NOTE: Vyper produces multiple signatures for a given function with \"default\" args\n    function withdraw() external returns (uint256);\n\n    function withdraw(uint256 maxShares) external returns (uint256);\n\n    function withdraw(uint256 maxShares, address recipient)\n        external\n        returns (uint256);\n\n    function token() external view returns (address);\n\n    function strategies(address _strategy)\n        external\n        view\n        returns (StrategyParams memory);\n\n    function pricePerShare() external view returns (uint256);\n\n    function totalAssets() external view returns (uint256);\n\n    function depositLimit() external view returns (uint256);\n\n    function maxAvailableShares() external view returns (uint256);\n\n    /**\n     * View how much the Vault would increase this Strategy's borrow limit,\n     * based on its present performance (since its last report). Can be used to\n     * determine expectedReturn in your Strategy.\n     */\n    function creditAvailable() external view returns (uint256);\n\n    /**\n     * View how much the Vault would like to pull back from the Strategy,\n     * based on its present performance (since its last report). Can be used to\n     * determine expectedReturn in your Strategy.\n     */\n    function debtOutstanding() external view returns (uint256);\n\n    /**\n     * View how much the Vault expect this Strategy to return at the current\n     * block, based on its present performance (since its last report). Can be\n     * used to determine expectedReturn in your Strategy.\n     */\n    function expectedReturn() external view returns (uint256);\n\n    /**\n     * This is the main contact point where the Strategy interacts with the\n     * Vault. It is critical that this call is handled as intended by the\n     * Strategy. Therefore, this function will be called by BaseStrategy to\n     * make sure the integration is correct.\n     */\n    function report(\n        uint256 _gain,\n        uint256 _loss,\n        uint256 _debtPayment\n    ) external returns (uint256);\n\n    /**\n     * This function should only be used in the scenario where the Strategy is\n     * being retired but no migration of the positions are possible, or in the\n     * extreme scenario that the Strategy needs to be put into \"Emergency Exit\"\n     * mode in order for it to exit as quickly as possible. The latter scenario\n     * could be for any reason that is considered \"critical\" that the Strategy\n     * exits its position as fast as possible, such as a sudden change in\n     * market conditions leading to losses, or an imminent failure in an\n     * external dependency.\n     */\n    function revokeStrategy() external;\n\n    /**\n     * View the governance address of the Vault to assert privileged functions\n     * can only be called by governance. The Strategy serves the Vault, so it\n     * is subject to governance defined by the Vault.\n     */\n    function governance() external view returns (address);\n\n    /**\n     * View the management address of the Vault to assert privileged functions\n     * can only be called by management. The Strategy serves the Vault, so it\n     * is subject to management defined by the Vault.\n     */\n    function management() external view returns (address);\n\n    /**\n     * View the guardian address of the Vault to assert privileged functions\n     * can only be called by guardian. The Strategy serves the Vault, so it\n     * is subject to guardian defined by the Vault.\n     */\n    function guardian() external view returns (address);\n}\n\n/**\n * This interface is here for the keeper bot to use.\n */\ninterface StrategyAPI {\n    function name() external view returns (string memory);\n\n    function vault() external view returns (address);\n\n    function want() external view returns (address);\n\n    function apiVersion() external pure returns (string memory);\n\n    function keeper() external view returns (address);\n\n    function isActive() external view returns (bool);\n\n    function delegatedAssets() external view returns (uint256);\n\n    function estimatedTotalAssets() external view returns (uint256);\n\n    function tendTrigger(uint256 callCost) external view returns (bool);\n\n    function tend() external;\n\n    function harvestTrigger(uint256 callCost) external view returns (bool);\n\n    function harvest() external;\n\n    event Harvested(\n        uint256 profit,\n        uint256 loss,\n        uint256 debtPayment,\n        uint256 debtOutstanding\n    );\n}\n\n/**\n * @title Yearn Base Strategy\n * @author yearn.finance\n * @notice\n *  BaseStrategy implements all of the required functionality to interoperate\n *  closely with the Vault contract. This contract should be inherited and the\n *  abstract methods implemented to adapt the Strategy to the particular needs\n *  it has to create a return.\n *\n *  Of special interest is the relationship between `harvest()` and\n *  `vault.report()'. `harvest()` may be called simply because enough time has\n *  elapsed since the last report, and not because any funds need to be moved\n *  or positions adjusted. This is critical so that the Vault may maintain an\n *  accurate picture of the Strategy's performance. See  `vault.report()`,\n *  `harvest()`, and `harvestTrigger()` for further details.\n */\n\nabstract contract BaseStrategy {\n    using SafeMath for uint256;\n    string public metadataURI;\n\n    /**\n     * @notice\n     *  Used to track which version of `StrategyAPI` this Strategy\n     *  implements.\n     * @dev The Strategy's version must match the Vault's `API_VERSION`.\n     * @return A string which holds the current API version of this contract.\n     */\n    function apiVersion() public pure returns (string memory) {\n        return \"0.4.2\";\n    }\n\n    /**\n     * @notice This Strategy's name.\n     * @dev\n     *  You can use this field to manage the \"version\" of this Strategy, e.g.\n     *  `StrategySomethingOrOtherV1`. However, \"API Version\" is managed by\n     *  `apiVersion()` function above.\n     * @return This Strategy's name.\n     */\n    function name() external view virtual returns (string memory);\n\n    /**\n     * @notice\n     *  The amount (priced in want) of the total assets managed by this strategy should not count\n     *  towards Yearn's TVL calculations.\n     * @dev\n     *  You can override this field to set it to a non-zero value if some of the assets of this\n     *  Strategy is somehow delegated inside another part of of Yearn's ecosystem e.g. another Vault.\n     *  Note that this value must be strictly less than or equal to the amount provided by\n     *  `estimatedTotalAssets()` below, as the TVL calc will be total assets minus delegated assets.\n     *  Also note that this value is used to determine the total assets under management by this\n     *  strategy, for the purposes of computing the management fee in `Vault`\n     * @return\n     *  The amount of assets this strategy manages that should not be included in Yearn's Total Value\n     *  Locked (TVL) calculation across it's ecosystem.\n     */\n    function delegatedAssets() external view virtual returns (uint256) {\n        return 0;\n    }\n\n    VaultAPI public vault;\n    address public strategist;\n    address public rewards;\n    address public keeper;\n\n    IERC20 public want;\n\n    // So indexers can keep track of this\n    event Harvested(\n        uint256 profit,\n        uint256 loss,\n        uint256 debtPayment,\n        uint256 debtOutstanding\n    );\n\n    event UpdatedStrategist(address newStrategist);\n\n    event UpdatedKeeper(address newKeeper);\n\n    event UpdatedRewards(address rewards);\n\n    event UpdatedMinReportDelay(uint256 delay);\n\n    event UpdatedMaxReportDelay(uint256 delay);\n\n    event UpdatedProfitFactor(uint256 profitFactor);\n\n    event UpdatedDebtThreshold(uint256 debtThreshold);\n\n    event EmergencyExitEnabled();\n\n    event UpdatedMetadataURI(string metadataURI);\n\n    // The minimum number of seconds between harvest calls. See\n    // `setMinReportDelay()` for more details.\n    uint256 public minReportDelay;\n\n    // The maximum number of seconds between harvest calls. See\n    // `setMaxReportDelay()` for more details.\n    uint256 public maxReportDelay;\n\n    // The minimum multiple that `callCost` must be above the credit/profit to\n    // be \"justifiable\". See `setProfitFactor()` for more details.\n    uint256 public profitFactor;\n\n    // Use this to adjust the threshold at which running a debt causes a\n    // harvest trigger. See `setDebtThreshold()` for more details.\n    uint256 public debtThreshold;\n\n    // See note on `setEmergencyExit()`.\n    bool public emergencyExit;\n\n    // modifiers\n    modifier onlyAuthorized() {\n        require(\n            msg.sender == strategist || msg.sender == governance(),\n            \"!authorized\"\n        );\n        _;\n    }\n\n    modifier onlyEmergencyAuthorized() {\n        require(\n            msg.sender == strategist ||\n                msg.sender == governance() ||\n                msg.sender == vault.guardian() ||\n                msg.sender == vault.management(),\n            \"!authorized\"\n        );\n        _;\n    }\n\n    modifier onlyStrategist() {\n        require(msg.sender == strategist, \"!strategist\");\n        _;\n    }\n\n    modifier onlyGovernance() {\n        require(msg.sender == governance(), \"!authorized\");\n        _;\n    }\n\n    modifier onlyKeepers() {\n        require(\n            msg.sender == keeper ||\n                msg.sender == strategist ||\n                msg.sender == governance() ||\n                msg.sender == vault.guardian() ||\n                msg.sender == vault.management(),\n            \"!authorized\"\n        );\n        _;\n    }\n\n    constructor(address _vault) {\n        _initialize(_vault, msg.sender, msg.sender, msg.sender);\n    }\n\n    /**\n     * @notice\n     *  Initializes the Strategy, this is called only once, when the\n     *  contract is deployed.\n     * @dev `_vault` should implement `VaultAPI`.\n     * @param _vault The address of the Vault responsible for this Strategy.\n     * @param _strategist The address to assign as `strategist`.\n     * The strategist is able to change the reward address\n     * @param _rewards  The address to use for pulling rewards.\n     * @param _keeper The adddress of the _keeper. _keeper\n     * can harvest and tend a strategy.\n     */\n    function _initialize(\n        address _vault,\n        address _strategist,\n        address _rewards,\n        address _keeper\n    ) internal {\n        require(address(want) == address(0), \"Strategy already initialized\");\n\n        vault = VaultAPI(_vault);\n        want = IERC20(vault.token());\n        SafeERC20.safeApprove(want, _vault, type(uint256).max); // Give Vault unlimited access (might save gas)\n        strategist = _strategist;\n        rewards = _rewards;\n        keeper = _keeper;\n\n        // initialize variables\n        minReportDelay = 0;\n        maxReportDelay = 86400;\n        profitFactor = 100;\n        debtThreshold = 0;\n\n        vault.approve(rewards, type(uint256).max); // Allow rewards to be pulled\n    }\n\n    /**\n     * @notice\n     *  Used to change `strategist`.\n     *\n     *  This may only be called by governance or the existing strategist.\n     * @param _strategist The new address to assign as `strategist`.\n     */\n    function setStrategist(address _strategist) external onlyAuthorized {\n        require(_strategist != address(0));\n        strategist = _strategist;\n        emit UpdatedStrategist(_strategist);\n    }\n\n    /**\n     * @notice\n     *  Used to change `keeper`.\n     *\n     *  `keeper` is the only address that may call `tend()` or `harvest()`,\n     *  other than `governance()` or `strategist`. However, unlike\n     *  `governance()` or `strategist`, `keeper` may *only* call `tend()`\n     *  and `harvest()`, and no other authorized functions, following the\n     *  principle of least privilege.\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _keeper The new address to assign as `keeper`.\n     */\n    function setKeeper(address _keeper) external onlyAuthorized {\n        require(_keeper != address(0));\n        keeper = _keeper;\n        emit UpdatedKeeper(_keeper);\n    }\n\n    /**\n     * @notice\n     *  Used to change `rewards`. EOA or smart contract which has the permission\n     *  to pull rewards from the vault.\n     *\n     *  This may only be called by the strategist.\n     * @param _rewards The address to use for pulling rewards.\n     */\n    function setRewards(address _rewards) external onlyStrategist {\n        require(_rewards != address(0));\n        vault.approve(rewards, 0);\n        rewards = _rewards;\n        vault.approve(rewards, type(uint256).max);\n        emit UpdatedRewards(_rewards);\n    }\n\n    /**\n     * @notice\n     *  Used to change `minReportDelay`. `minReportDelay` is the minimum number\n     *  of blocks that should pass for `harvest()` to be called.\n     *\n     *  For external keepers (such as the Keep3r network), this is the minimum\n     *  time between jobs to wait. (see `harvestTrigger()`\n     *  for more details.)\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _delay The minimum number of seconds to wait between harvests.\n     */\n    function setMinReportDelay(uint256 _delay) external onlyAuthorized {\n        minReportDelay = _delay;\n        emit UpdatedMinReportDelay(_delay);\n    }\n\n    /**\n     * @notice\n     *  Used to change `maxReportDelay`. `maxReportDelay` is the maximum number\n     *  of blocks that should pass for `harvest()` to be called.\n     *\n     *  For external keepers (such as the Keep3r network), this is the maximum\n     *  time between jobs to wait. (see `harvestTrigger()`\n     *  for more details.)\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _delay The maximum number of seconds to wait between harvests.\n     */\n    function setMaxReportDelay(uint256 _delay) external onlyAuthorized {\n        maxReportDelay = _delay;\n        emit UpdatedMaxReportDelay(_delay);\n    }\n\n    /**\n     * @notice\n     *  Used to change `profitFactor`. `profitFactor` is used to determine\n     *  if it's worthwhile to harvest, given gas costs. (See `harvestTrigger()`\n     *  for more details.)\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _profitFactor A ratio to multiply anticipated\n     * `harvest()` gas cost against.\n     */\n    function setProfitFactor(uint256 _profitFactor) external onlyAuthorized {\n        profitFactor = _profitFactor;\n        emit UpdatedProfitFactor(_profitFactor);\n    }\n\n    /**\n     * @notice\n     *  Sets how far the Strategy can go into loss without a harvest and report\n     *  being required.\n     *\n     *  By default this is 0, meaning any losses would cause a harvest which\n     *  will subsequently report the loss to the Vault for tracking. (See\n     *  `harvestTrigger()` for more details.)\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _debtThreshold How big of a loss this Strategy may carry without\n     * being required to report to the Vault.\n     */\n    function setDebtThreshold(uint256 _debtThreshold) external onlyAuthorized {\n        debtThreshold = _debtThreshold;\n        emit UpdatedDebtThreshold(_debtThreshold);\n    }\n\n    /**\n     * @notice\n     *  Used to change `metadataURI`. `metadataURI` is used to store the URI\n     * of the file describing the strategy.\n     *\n     *  This may only be called by governance or the strategist.\n     * @param _metadataURI The URI that describe the strategy.\n     */\n    function setMetadataURI(string calldata _metadataURI)\n        external\n        onlyAuthorized\n    {\n        metadataURI = _metadataURI;\n        emit UpdatedMetadataURI(_metadataURI);\n    }\n\n    /**\n     * Resolve governance address from Vault contract, used to make assertions\n     * on protected functions in the Strategy.\n     */\n    function governance() internal view returns (address) {\n        return vault.governance();\n    }\n\n    /**\n     * @notice\n     *  Provide an accurate conversion from `_amtInWei` (denominated in wei)\n     *  to `want` (using the native decimal characteristics of `want`).\n     * @dev\n     *  Care must be taken when working with decimals to assure that the conversion\n     *  is compatible. As an example:\n     *\n     *      given 1e17 wei (0.1 ETH) as input, and want is USDC (6 decimals),\n     *      with USDC/ETH = 1800, this should give back 1800000000 (180 USDC)\n     *\n     * @param _amtInWei The amount (in wei/1e-18 ETH) to convert to `want`\n     * @return The amount in `want` of `_amtInEth` converted to `want`\n     **/\n    function ethToWant(uint256 _amtInWei) public view virtual returns (uint256);\n\n    /**\n     * @notice\n     *  Provide an accurate estimate for the total amount of assets\n     *  (principle + return) that this Strategy is currently managing,\n     *  denominated in terms of `want` tokens.\n     *\n     *  This total should be \"realizable\" e.g. the total value that could\n     *  *actually* be obtained from this Strategy if it were to divest its\n     *  entire position based on current on-chain conditions.\n     * @dev\n     *  Care must be taken in using this function, since it relies on external\n     *  systems, which could be manipulated by the attacker to give an inflated\n     *  (or reduced) value produced by this function, based on current on-chain\n     *  conditions (e.g. this function is possible to influence through\n     *  flashloan attacks, oracle manipulations, or other DeFi attack\n     *  mechanisms).\n     *\n     *  It is up to governance to use this function to correctly order this\n     *  Strategy relative to its peers in the withdrawal queue to minimize\n     *  losses for the Vault based on sudden withdrawals. This value should be\n     *  higher than the total debt of the Strategy and higher than its expected\n     *  value to be \"safe\".\n     * @return The estimated total assets in this Strategy.\n     */\n    function estimatedTotalAssets() public view virtual returns (uint256);\n\n    /*\n     * @notice\n     *  Provide an indication of whether this strategy is currently \"active\"\n     *  in that it is managing an active position, or will manage a position in\n     *  the future. This should correlate to `harvest()` activity, so that Harvest\n     *  events can be tracked externally by indexing agents.\n     * @return True if the strategy is actively managing a position.\n     */\n    function isActive() public view returns (bool) {\n        return\n            vault.strategies(address(this)).debtRatio > 0 ||\n            estimatedTotalAssets() > 0;\n    }\n\n    /**\n     * Perform any Strategy unwinding or other calls necessary to capture the\n     * \"free return\" this Strategy has generated since the last time its core\n     * position(s) were adjusted. Examples include unwrapping extra rewards.\n     * This call is only used during \"normal operation\" of a Strategy, and\n     * should be optimized to minimize losses as much as possible.\n     *\n     * This method returns any realized profits and/or realized losses\n     * incurred, and should return the total amounts of profits/losses/debt\n     * payments (in `want` tokens) for the Vault's accounting (e.g.\n     * `want.balanceOf(this) >= _debtPayment + _profit`).\n     *\n     * `_debtOutstanding` will be 0 if the Strategy is not past the configured\n     * debt limit, otherwise its value will be how far past the debt limit\n     * the Strategy is. The Strategy's debt limit is configured in the Vault.\n     *\n     * NOTE: `_debtPayment` should be less than or equal to `_debtOutstanding`.\n     *       It is okay for it to be less than `_debtOutstanding`, as that\n     *       should only used as a guide for how much is left to pay back.\n     *       Payments should be made to minimize loss from slippage, debt,\n     *       withdrawal fees, etc.\n     *\n     * See `vault.debtOutstanding()`.\n     */\n    function prepareReturn(uint256 _debtOutstanding)\n        internal\n        virtual\n        returns (\n            uint256 _profit,\n            uint256 _loss,\n            uint256 _debtPayment\n        );\n\n    /**\n     * Perform any adjustments to the core position(s) of this Strategy given\n     * what change the Vault made in the \"investable capital\" available to the\n     * Strategy. Note that all \"free capital\" in the Strategy after the report\n     * was made is available for reinvestment. Also note that this number\n     * could be 0, and you should handle that scenario accordingly.\n     *\n     * See comments regarding `_debtOutstanding` on `prepareReturn()`.\n     */\n    function adjustPosition(uint256 _debtOutstanding) internal virtual;\n\n    /**\n     * Liquidate up to `_amountNeeded` of `want` of this strategy's positions,\n     * irregardless of slippage. Any excess will be re-invested with `adjustPosition()`.\n     * This function should return the amount of `want` tokens made available by the\n     * liquidation. If there is a difference between them, `_loss` indicates whether the\n     * difference is due to a realized loss, or if there is some other sitution at play\n     * (e.g. locked funds) where the amount made available is less than what is needed.\n     *\n     * NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained\n     */\n    function liquidatePosition(uint256 _amountNeeded)\n        internal\n        virtual\n        returns (uint256 _liquidatedAmount, uint256 _loss);\n\n    /**\n     * Liquidate everything and returns the amount that got freed.\n     * This function is used during emergency exit instead of `prepareReturn()` to\n     * liquidate all of the Strategy's positions back to the Vault.\n     */\n\n    function liquidateAllPositions()\n        internal\n        virtual\n        returns (uint256 _amountFreed);\n\n    /**\n     * @notice\n     *  Provide a signal to the keeper that `tend()` should be called. The\n     *  keeper will provide the estimated gas cost that they would pay to call\n     *  `tend()`, and this function should use that estimate to make a\n     *  determination if calling it is \"worth it\" for the keeper. This is not\n     *  the only consideration into issuing this trigger, for example if the\n     *  position would be negatively affected if `tend()` is not called\n     *  shortly, then this can return `true` even if the keeper might be\n     *  \"at a loss\" (keepers are always reimbursed by Yearn).\n     * @dev\n     *  `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).\n     *\n     *  This call and `harvestTrigger()` should never return `true` at the same\n     *  time.\n     * @param callCostInWei The keeper's estimated gas cost to call `tend()` (in wei).\n     * @return `true` if `tend()` should be called, `false` otherwise.\n     */\n    function tendTrigger(uint256 callCostInWei)\n        public\n        view\n        virtual\n        returns (bool)\n    {\n        // We usually don't need tend, but if there are positions that need\n        // active maintainence, overriding this function is how you would\n        // signal for that.\n        // If your implementation uses the cost of the call in want, you can\n        // use uint256 callCost = ethToWant(callCostInWei);\n\n        return false;\n    }\n\n    /**\n     * @notice\n     *  Adjust the Strategy's position. The purpose of tending isn't to\n     *  realize gains, but to maximize yield by reinvesting any returns.\n     *\n     *  See comments on `adjustPosition()`.\n     *\n     *  This may only be called by governance, the strategist, or the keeper.\n     */\n    function tend() external onlyKeepers {\n        // Don't take profits with this call, but adjust for better gains\n        adjustPosition(vault.debtOutstanding());\n    }\n\n    /**\n     * @notice\n     *  Provide a signal to the keeper that `harvest()` should be called. The\n     *  keeper will provide the estimated gas cost that they would pay to call\n     *  `harvest()`, and this function should use that estimate to make a\n     *  determination if calling it is \"worth it\" for the keeper. This is not\n     *  the only consideration into issuing this trigger, for example if the\n     *  position would be negatively affected if `harvest()` is not called\n     *  shortly, then this can return `true` even if the keeper might be \"at a\n     *  loss\" (keepers are always reimbursed by Yearn).\n     * @dev\n     *  `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).\n     *\n     *  This call and `tendTrigger` should never return `true` at the\n     *  same time.\n     *\n     *  See `min/maxReportDelay`, `profitFactor`, `debtThreshold` to adjust the\n     *  strategist-controlled parameters that will influence whether this call\n     *  returns `true` or not. These parameters will be used in conjunction\n     *  with the parameters reported to the Vault (see `params`) to determine\n     *  if calling `harvest()` is merited.\n     *\n     *  It is expected that an external system will check `harvestTrigger()`.\n     *  This could be a script run off a desktop or cloud bot (e.g.\n     *  https://github.com/iearn-finance/yearn-vaults/blob/master/scripts/keep.py),\n     *  or via an integration with the Keep3r network (e.g.\n     *  https://github.com/Macarse/GenericKeep3rV2/blob/master/contracts/keep3r/GenericKeep3rV2.sol).\n     * @param callCostInWei The keeper's estimated gas cost to call `harvest()` (in wei).\n     * @return `true` if `harvest()` should be called, `false` otherwise.\n     */\n    function harvestTrigger(uint256 callCostInWei)\n        public\n        view\n        virtual\n        returns (bool)\n    {\n        uint256 callCost = ethToWant(callCostInWei);\n        StrategyParams memory params = vault.strategies(address(this));\n\n        // Should not trigger if Strategy is not activated\n        if (params.activation == 0) return false;\n\n        // Should not trigger if we haven't waited long enough since previous harvest\n        if (block.timestamp.sub(params.lastReport) < minReportDelay)\n            return false;\n\n        // Should trigger if hasn't been called in a while\n        if (block.timestamp.sub(params.lastReport) >= maxReportDelay)\n            return true;\n\n        // If some amount is owed, pay it back\n        // NOTE: Since debt is based on deposits, it makes sense to guard against large\n        //       changes to the value from triggering a harvest directly through user\n        //       behavior. This should ensure reasonable resistance to manipulation\n        //       from user-initiated withdrawals as the outstanding debt fluctuates.\n        uint256 outstanding = vault.debtOutstanding();\n        if (outstanding > debtThreshold) return true;\n\n        // Check for profits and losses\n        uint256 total = estimatedTotalAssets();\n        // Trigger if we have a loss to report\n        if (total.add(debtThreshold) < params.totalDebt) return true;\n\n        uint256 profit = 0;\n        if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!\n\n        // Otherwise, only trigger if it \"makes sense\" economically (gas cost\n        // is <N% of value moved)\n        uint256 credit = vault.creditAvailable();\n        return (profitFactor.mul(callCost) < credit.add(profit));\n    }\n\n    /**\n     * @notice\n     *  Harvests the Strategy, recognizing any profits or losses and adjusting\n     *  the Strategy's position.\n     *\n     *  In the rare case the Strategy is in emergency shutdown, this will exit\n     *  the Strategy's position.\n     *\n     *  This may only be called by governance, the strategist, or the keeper.\n     * @dev\n     *  When `harvest()` is called, the Strategy reports to the Vault (via\n     *  `vault.report()`), so in some cases `harvest()` must be called in order\n     *  to take in profits, to borrow newly available funds from the Vault, or\n     *  otherwise adjust its position. In other cases `harvest()` must be\n     *  called to report to the Vault on the Strategy's position, especially if\n     *  any losses have occurred.\n     */\n    function harvest() external onlyKeepers {\n        uint256 profit = 0;\n        uint256 loss = 0;\n        uint256 debtOutstanding = vault.debtOutstanding();\n        uint256 debtPayment = 0;\n        if (emergencyExit) {\n            // Free up as much capital as possible\n            uint256 amountFreed = liquidateAllPositions();\n            if (amountFreed < debtOutstanding) {\n                loss = debtOutstanding.sub(amountFreed);\n            } else if (amountFreed > debtOutstanding) {\n                profit = amountFreed.sub(debtOutstanding);\n            }\n            debtPayment = debtOutstanding.sub(loss);\n        } else {\n            // Free up returns for Vault to pull\n            (profit, loss, debtPayment) = prepareReturn(debtOutstanding);\n        }\n\n        // Allow Vault to take up to the \"harvested\" balance of this contract,\n        // which is the amount it has earned since the last time it reported to\n        // the Vault.\n        debtOutstanding = vault.report(profit, loss, debtPayment);\n\n        // Check if free returns are left, and re-invest them\n        adjustPosition(debtOutstanding);\n\n        emit Harvested(profit, loss, debtPayment, debtOutstanding);\n    }\n\n    /**\n     * @notice\n     *  Withdraws `_amountNeeded` to `vault`.\n     *\n     *  This may only be called by the Vault.\n     * @param _amountNeeded How much `want` to withdraw.\n     * @return _loss Any realized losses\n     */\n    function withdraw(uint256 _amountNeeded) external returns (uint256 _loss) {\n        require(msg.sender == address(vault), \"!vault\");\n        // Liquidate as much as possible to `want`, up to `_amountNeeded`\n        uint256 amountFreed;\n        (amountFreed, _loss) = liquidatePosition(_amountNeeded);\n        // Send it directly back (NOTE: Using `msg.sender` saves some gas here)\n        SafeERC20.safeTransfer(want, msg.sender, amountFreed);\n        // NOTE: Reinvest anything leftover on next `tend`/`harvest`\n    }\n\n    /**\n     * Do anything necessary to prepare this Strategy for migration, such as\n     * transferring any reserve or LP tokens, CDPs, or other tokens or stores of\n     * value.\n     */\n    function prepareMigration(address _newStrategy) internal virtual;\n\n    /**\n     * @notice\n     *  Transfers all `want` from this Strategy to `_newStrategy`.\n     *\n     *  This may only be called by the Vault.\n     * @dev\n     * The new Strategy's Vault must be the same as this Strategy's Vault.\n     *  The migration process should be carefully performed to make sure all\n     * the assets are migrated to the new address, which should have never\n     * interacted with the vault before.\n     * @param _newStrategy The Strategy to migrate to.\n     */\n    function migrate(address _newStrategy) external {\n        require(msg.sender == address(vault));\n        require(BaseStrategy(_newStrategy).vault() == vault);\n        prepareMigration(_newStrategy);\n        SafeERC20.safeTransfer(\n            want,\n            _newStrategy,\n            want.balanceOf(address(this))\n        );\n    }\n\n    /**\n     * @notice\n     *  Activates emergency exit. Once activated, the Strategy will exit its\n     *  position upon the next harvest, depositing all funds into the Vault as\n     *  quickly as is reasonable given on-chain conditions.\n     *\n     *  This may only be called by governance or the strategist.\n     * @dev\n     *  See `vault.setEmergencyShutdown()` and `harvest()` for further details.\n     */\n    function setEmergencyExit() external onlyEmergencyAuthorized {\n        emergencyExit = true;\n        vault.revokeStrategy();\n\n        emit EmergencyExitEnabled();\n    }\n\n    /**\n     * Override this to add all tokens/tokenized positions this contract\n     * manages on a *persistent* basis (e.g. not just for swapping back to\n     * want ephemerally).\n     *\n     * NOTE: Do *not* include `want`, already included in `sweep` below.\n     *\n     * Example:\n     * ```\n     *    function protectedTokens() internal override view returns (address[] memory) {\n     *      address[] memory protected = new address[](3);\n     *      protected[0] = tokenA;\n     *      protected[1] = tokenB;\n     *      protected[2] = tokenC;\n     *      return protected;\n     *    }\n     * ```\n     */\n    function protectedTokens() internal view virtual returns (address[] memory);\n\n    /**\n     * @notice\n     *  Removes tokens from this Strategy that are not the type of tokens\n     *  managed by this Strategy. This may be used in case of accidentally\n     *  sending the wrong kind of token to this Strategy.\n     *\n     *  Tokens will be sent to `governance()`.\n     *\n     *  This will fail if an attempt is made to sweep `want`, or any tokens\n     *  that are protected by this Strategy.\n     *\n     *  This may only be called by governance.\n     * @dev\n     *  Implement `protectedTokens()` to specify any additional tokens that\n     *  should be protected from sweeping in addition to `want`.\n     * @param _token The token to transfer out of this vault.\n     */\n    function sweep(address _token) external onlyGovernance {\n        require(_token != address(want), \"!want\");\n        require(_token != address(vault), \"!shares\");\n\n        address[] memory _protectedTokens = protectedTokens();\n        for (uint256 i; i < _protectedTokens.length; i++)\n            require(_token != _protectedTokens[i], \"!protected\");\n\n        SafeERC20.safeTransfer(\n            IERC20(_token),\n            governance(),\n            IERC20(_token).balanceOf(address(this))\n        );\n    }\n}\n\nabstract contract BaseStrategyInitializable is BaseStrategy {\n    bool public isOriginal = true;\n    event Cloned(address indexed clone);\n\n    constructor(address _vault) BaseStrategy(_vault) {}\n\n    function initialize(\n        address _vault,\n        address _strategist,\n        address _rewards,\n        address _keeper\n    ) external virtual {\n        _initialize(_vault, _strategist, _rewards, _keeper);\n    }\n\n    function clone(address _vault) external returns (address) {\n        require(isOriginal, \"!clone\");\n        return this.clone(_vault, msg.sender, msg.sender, msg.sender);\n    }\n\n    function clone(\n        address _vault,\n        address _strategist,\n        address _rewards,\n        address _keeper\n    ) external returns (address newStrategy) {\n        // Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol\n        bytes20 addressBytes = bytes20(address(this));\n\n        assembly {\n            // EIP-1167 bytecode\n            let clone_code := mload(0x40)\n            mstore(\n                clone_code,\n                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000\n            )\n            mstore(add(clone_code, 0x14), addressBytes)\n            mstore(\n                add(clone_code, 0x28),\n                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000\n            )\n            newStrategy := create(0, clone_code, 0x37)\n        }\n\n        BaseStrategyInitializable(newStrategy).initialize(\n            _vault,\n            _strategist,\n            _rewards,\n            _keeper\n        );\n\n        emit Cloned(newStrategy);\n    }\n}\n"},{"file_path":"./contracts/helpers/yearn/BaseWrapper.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\npragma abicoder v2;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {SafeMath} from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport {VaultAPI} from \"./BaseStrategy.sol\";\n\ninterface RegistryAPI {\n    function governance() external view returns (address);\n\n    function latestVault(address token) external view returns (address);\n\n    function numVaults(address token) external view returns (uint256);\n\n    function vaults(address token, uint256 deploymentId)\n        external\n        view\n        returns (address);\n}\n\n/**\n * @title Yearn Base Wrapper\n * @author yearn.finance\n * @notice\n *  BaseWrapper implements all of the required functionality to interoperate\n *  closely with the Vault contract. This contract should be inherited and the\n *  abstract methods implemented to adapt the Wrapper.\n *  A good starting point to build a wrapper is https://github.com/yearn/brownie-wrapper-mix\n *\n */\nabstract contract BaseWrapper {\n    using Math for uint256;\n    using SafeMath for uint256;\n\n    IERC20 public token;\n\n    // Reduce number of external calls (SLOADs stay the same)\n    VaultAPI[] private _cachedVaults;\n\n    RegistryAPI public registry;\n\n    // ERC20 Unlimited Approvals (short-circuits VaultAPI.transferFrom)\n    uint256 constant UNLIMITED_APPROVAL = type(uint256).max;\n    // Sentinal values used to save gas on deposit/withdraw/migrate\n    // NOTE: DEPOSIT_EVERYTHING == WITHDRAW_EVERYTHING == MIGRATE_EVERYTHING\n    uint256 constant DEPOSIT_EVERYTHING = type(uint256).max;\n    uint256 constant WITHDRAW_EVERYTHING = type(uint256).max;\n    uint256 constant MIGRATE_EVERYTHING = type(uint256).max;\n    // VaultsAPI.depositLimit is unlimited\n    uint256 constant UNCAPPED_DEPOSITS = type(uint256).max;\n\n    constructor(address _token, address _registry) {\n        // Recommended to use a token with a `Registry.latestVault(_token) != address(0)`\n        token = IERC20(_token);\n        // Recommended to use `v2.registry.ychad.eth`\n        registry = RegistryAPI(_registry);\n    }\n\n    /**\n     * @notice\n     *  Used to update the yearn registry.\n     * @param _registry The new _registry address.\n     */\n    function setRegistry(address _registry) external {\n        require(msg.sender == registry.governance());\n        // In case you want to override the registry instead of re-deploying\n        registry = RegistryAPI(_registry);\n        // Make sure there's no change in governance\n        // NOTE: Also avoid bricking the wrapper from setting a bad registry\n        require(msg.sender == registry.governance());\n    }\n\n    /**\n     * @notice\n     *  Used to get the most revent vault for the token using the registry.\n     * @return An instance of a VaultAPI\n     */\n    function bestVault() public view virtual returns (VaultAPI) {\n        return VaultAPI(registry.latestVault(address(token)));\n    }\n\n    /**\n     * @notice\n     *  Used to get all vaults from the registery for the token\n     * @return An array containing instances of VaultAPI\n     */\n    function allVaults() public view virtual returns (VaultAPI[] memory) {\n        uint256 cache_length = _cachedVaults.length;\n        uint256 num_vaults = registry.numVaults(address(token));\n\n        // Use cached\n        if (cache_length == num_vaults) {\n            return _cachedVaults;\n        }\n\n        VaultAPI[] memory vaults = new VaultAPI[](num_vaults);\n\n        for (uint256 vault_id = 0; vault_id < cache_length; vault_id++) {\n            vaults[vault_id] = _cachedVaults[vault_id];\n        }\n\n        for (\n            uint256 vault_id = cache_length;\n            vault_id < num_vaults;\n            vault_id++\n        ) {\n            vaults[vault_id] = VaultAPI(\n                registry.vaults(address(token), vault_id)\n            );\n        }\n\n        return vaults;\n    }\n\n    function _updateVaultCache(VaultAPI[] memory vaults) internal {\n        // NOTE: even though `registry` is update-able by Yearn, the intended behavior\n        //       is that any future upgrades to the registry will replay the version\n        //       history so that this cached value does not get out of date.\n        if (vaults.length > _cachedVaults.length) {\n            _cachedVaults = vaults;\n        }\n    }\n\n    /**\n     * @notice\n     *  Used to get the balance of an account accross all the vaults for a token.\n     *  @dev will be used to get the wrapper balance using totalVaultBalance(address(this)).\n     *  @param account The address of the account.\n     *  @return balance of token for the account accross all the vaults.\n     */\n    function totalVaultBalance(address account)\n        public\n        view\n        returns (uint256 balance)\n    {\n        VaultAPI[] memory vaults = allVaults();\n\n        for (uint256 id = 0; id < vaults.length; id++) {\n            balance = balance.add(\n                vaults[id]\n                .balanceOf(account)\n                .mul(vaults[id].pricePerShare())\n                .div(10**uint256(vaults[id].decimals()))\n            );\n        }\n    }\n\n    /**\n     * @notice\n     *  Used to get the TVL on the underlying vaults.\n     *  @return assets the sum of all the assets managed by the underlying vaults.\n     */\n    function totalAssets() public view returns (uint256 assets) {\n        VaultAPI[] memory vaults = allVaults();\n\n        for (uint256 id = 0; id < vaults.length; id++) {\n            assets = assets.add(vaults[id].totalAssets());\n        }\n    }\n\n    function _deposit(\n        address depositor,\n        address receiver,\n        uint256 amount, // if `MAX_UINT256`, just deposit everything\n        bool pullFunds // If true, funds need to be pulled from `depositor` via `transferFrom`\n    ) internal returns (uint256 deposited) {\n        VaultAPI _bestVault = bestVault();\n\n        if (pullFunds) {\n            if (amount != DEPOSIT_EVERYTHING) {\n                SafeERC20.safeTransferFrom(\n                    token,\n                    depositor,\n                    address(this),\n                    amount\n                );\n            } else {\n                SafeERC20.safeTransferFrom(\n                    token,\n                    depositor,\n                    address(this),\n                    token.balanceOf(depositor)\n                );\n            }\n        }\n\n        if (token.allowance(address(this), address(_bestVault)) < amount) {\n            SafeERC20.safeApprove(token, address(_bestVault), 0); // Avoid issues with some tokens requiring 0\n            SafeERC20.safeApprove(\n                token,\n                address(_bestVault),\n                UNLIMITED_APPROVAL\n            ); // Vaults are trusted\n        }\n\n        // Depositing returns number of shares deposited\n        // NOTE: Shortcut here is assuming the number of tokens deposited is equal to the\n        //       number of shares credited, which helps avoid an occasional multiplication\n        //       overflow if trying to adjust the number of shares by the share price.\n        uint256 beforeBal = token.balanceOf(address(this));\n        if (receiver != address(this)) {\n            _bestVault.deposit(amount, receiver);\n        } else if (amount != DEPOSIT_EVERYTHING) {\n            _bestVault.deposit(amount);\n        } else {\n            _bestVault.deposit();\n        }\n\n        uint256 afterBal = token.balanceOf(address(this));\n        deposited = beforeBal.sub(afterBal);\n        // `receiver` now has shares of `_bestVault` as balance, converted to `token` here\n        // Issue a refund if not everything was deposited\n        if (depositor != address(this) && afterBal > 0)\n            SafeERC20.safeTransfer(token, depositor, afterBal);\n    }\n\n    function _withdraw(\n        address sender,\n        address receiver,\n        uint256 amount, // if `MAX_UINT256`, just withdraw everything\n        bool withdrawFromBest // If true, also withdraw from `_bestVault`\n    ) internal returns (uint256 withdrawn) {\n        VaultAPI _bestVault = bestVault();\n\n        VaultAPI[] memory vaults = allVaults();\n        _updateVaultCache(vaults);\n\n        // NOTE: This loop will attempt to withdraw from each Vault in `allVaults` that `sender`\n        //       is deposited in, up to `amount` tokens. The withdraw action can be expensive,\n        //       so it if there is a denial of service issue in withdrawing, the downstream usage\n        //       of this wrapper contract must give an alternative method of withdrawing using\n        //       this function so that `amount` is less than the full amount requested to withdraw\n        //       (e.g. \"piece-wise withdrawals\"), leading to less loop iterations such that the\n        //       DoS issue is mitigated (at a tradeoff of requiring more txns from the end user).\n        for (uint256 id = 0; id < vaults.length; id++) {\n            if (!withdrawFromBest && vaults[id] == _bestVault) {\n                continue; // Don't withdraw from the best\n            }\n\n            // Start with the total shares that `sender` has\n            uint256 availableShares = vaults[id].balanceOf(sender);\n\n            // Restrict by the allowance that `sender` has to this contract\n            // NOTE: No need for allowance check if `sender` is this contract\n            if (sender != address(this)) {\n                availableShares = Math.min(\n                    availableShares,\n                    vaults[id].allowance(sender, address(this))\n                );\n            }\n\n            // Limit by maximum withdrawal size from each vault\n            availableShares = Math.min(\n                availableShares,\n                vaults[id].maxAvailableShares()\n            );\n\n            if (availableShares > 0) {\n                // Intermediate step to move shares to this contract before withdrawing\n                // NOTE: No need for share transfer if this contract is `sender`\n                if (sender != address(this))\n                    vaults[id].transferFrom(\n                        sender,\n                        address(this),\n                        availableShares\n                    );\n\n                if (amount != WITHDRAW_EVERYTHING) {\n                    // Compute amount to withdraw fully to satisfy the request\n                    uint256 estimatedShares = amount\n                    .sub(withdrawn) // NOTE: Changes every iteration\n                    .mul(10**uint256(vaults[id].decimals()))\n                    .div(vaults[id].pricePerShare()); // NOTE: Every Vault is different\n\n                    // Limit amount to withdraw to the maximum made available to this contract\n                    // NOTE: Avoid corner case where `estimatedShares` isn't precise enough\n                    // NOTE: If `0 < estimatedShares < 1` but `availableShares > 1`, this will withdraw more than necessary\n                    if (\n                        estimatedShares > 0 && estimatedShares < availableShares\n                    ) {\n                        withdrawn = withdrawn.add(\n                            vaults[id].withdraw(estimatedShares)\n                        );\n                    } else {\n                        withdrawn = withdrawn.add(\n                            vaults[id].withdraw(availableShares)\n                        );\n                    }\n                } else {\n                    withdrawn = withdrawn.add(vaults[id].withdraw());\n                }\n\n                // Check if we have fully satisfied the request\n                // NOTE: use `amount = WITHDRAW_EVERYTHING` for withdrawing everything\n                if (amount <= withdrawn) break; // withdrawn as much as we needed\n            }\n        }\n\n        // If we have extra, deposit back into `_bestVault` for `sender`\n        // NOTE: Invariant is `withdrawn <= amount`\n        if (\n            withdrawn > amount &&\n            withdrawn.sub(amount) >\n            _bestVault.pricePerShare().div(10**_bestVault.decimals())\n        ) {\n            // Don't forget to approve the deposit\n            if (\n                token.allowance(address(this), address(_bestVault)) <\n                withdrawn.sub(amount)\n            ) {\n                SafeERC20.safeApprove(\n                    token,\n                    address(_bestVault),\n                    UNLIMITED_APPROVAL\n                ); // Vaults are trusted\n            }\n\n            _bestVault.deposit(withdrawn.sub(amount), sender);\n            withdrawn = amount;\n        }\n\n        // `receiver` now has `withdrawn` tokens as balance\n        if (receiver != address(this))\n            SafeERC20.safeTransfer(token, receiver, withdrawn);\n    }\n\n    function _migrate(address account) internal returns (uint256) {\n        return _migrate(account, MIGRATE_EVERYTHING);\n    }\n\n    function _migrate(address account, uint256 amount)\n        internal\n        returns (uint256)\n    {\n        // NOTE: In practice, it was discovered that <50 was the maximum we've see for this variance\n        return _migrate(account, amount, 0);\n    }\n\n    function _migrate(\n        address account,\n        uint256 amount,\n        uint256 maxMigrationLoss\n    ) internal returns (uint256 migrated) {\n        VaultAPI _bestVault = bestVault();\n\n        // NOTE: Only override if we aren't migrating everything\n        uint256 _depositLimit = _bestVault.depositLimit();\n        uint256 _totalAssets = _bestVault.totalAssets();\n        if (_depositLimit <= _totalAssets) return 0; // Nothing to migrate (not a failure)\n\n        uint256 _amount = amount;\n        if (\n            _depositLimit < UNCAPPED_DEPOSITS && _amount < WITHDRAW_EVERYTHING\n        ) {\n            // Can only deposit up to this amount\n            uint256 _depositLeft = _depositLimit.sub(_totalAssets);\n            if (_amount > _depositLeft) _amount = _depositLeft;\n        }\n\n        if (_amount > 0) {\n            // NOTE: `false` = don't withdraw from `_bestVault`\n            uint256 withdrawn = _withdraw(\n                account,\n                address(this),\n                _amount,\n                false\n            );\n            if (withdrawn == 0) return 0; // Nothing to migrate (not a failure)\n\n            // NOTE: `false` = don't do `transferFrom` because it's already local\n            migrated = _deposit(address(this), account, withdrawn, false);\n            // NOTE: Due to the precision loss of certain calculations, there is a small inefficency\n            //       on how migrations are calculated, and this could lead to a DoS issue. Hence, this\n            //       value is made to be configurable to allow the user to specify how much is acceptable\n            require(withdrawn.sub(migrated) <= maxMigrationLoss);\n        } // else: nothing to migrate! (not a failure)\n    }\n}\n"},{"file_path":"./contracts/interfaces/IYapeFactory.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\nimport {IUniswapV2Factory} from \"../helpers/uni-v2/interfaces/IUniswapV2Factory.sol\";\n\ninterface IYapeFactory is IUniswapV2Factory {\n    function registry() external view returns (address);\n\n    function operator() external view returns (address);\n}\n"},{"file_path":"./contracts/interfaces/IYapePair.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0;\n\nimport {IUniswapV2Pair} from \"../helpers/uni-v2/interfaces/IUniswapV2Pair.sol\";\n\ninterface IYapePair is IUniswapV2Pair {\n    function updateRegistry() external;\n\n    function setFarmingRatio(uint256 min, uint256 max) external;\n\n    function migrate(address token) external returns (uint256);\n\n    function migrate(address token, uint256 amount) external returns (uint256);\n\n    function migrate(\n        address token,\n        uint256 amount,\n        uint256 maxMigrationLoss\n    ) external returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.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 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) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\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"},{"file_path":"@openzeppelin/contracts/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n        (bool success, ) = recipient.call{ value: amount }(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain`call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n      return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: value }(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                // solhint-disable-next-line no-inline-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a >= b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow, so we distribute\n        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SafeMath.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\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 a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator.\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b <= a, errorMessage);\n            return a - b;\n        }\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * 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     * 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        unchecked {\n            require(b > 0, errorMessage);\n            return a / b;\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a % b;\n        }\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"feeToSetter_","type":"address"},{"internalType":"address","name":"registry_","type":"address"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"pairCode_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairCode","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"registry_","type":"address"}],"name":"setRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000d8965d4fabfa616110ac8737c74f5e4948c6d95200000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e053804000000000000000000000000d8965d4fabfa616110ac8737c74f5e4948c6d9520000000000000000000000008b2b880303f65da62ae442a658d5d4170ee470d8"}