-
Notifications
You must be signed in to change notification settings - Fork 14
/
flat.json
1 lines (1 loc) · 104 KB
/
flat.json
1
{"flattened_source": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.6.12;\npragma experimental ABIEncoderV2;\n\n// Global Enums and Structs\n\n\n\nstruct StrategyParams {\n uint256 performanceFee;\n uint256 activation;\n uint256 debtRatio;\n uint256 rateLimit;\n uint256 lastReport;\n uint256 totalDebt;\n uint256 totalGain;\n uint256 totalLoss;\n}\n\n// Part: Account\n\nlibrary Account {\n enum Status {Normal, Liquid, Vapor}\n struct Info {\n address owner; // The address that owns the account\n uint256 number; // A nonce that allows a single address to control many accounts\n }\n struct Storage {\n mapping(uint256 => Types.Par) balances; // Mapping from marketId to principal\n Status status;\n }\n}\n\n// Part: Actions\n\nlibrary Actions {\n enum ActionType {\n Deposit, // supply tokens\n Withdraw, // borrow tokens\n Transfer, // transfer balance between accounts\n Buy, // buy an amount of some token (publicly)\n Sell, // sell an amount of some token (publicly)\n Trade, // trade tokens against another account\n Liquidate, // liquidate an undercollateralized or expiring account\n Vaporize, // use excess tokens to zero-out a completely negative account\n Call // send arbitrary data to an address\n }\n\n enum AccountLayout {OnePrimary, TwoPrimary, PrimaryAndSecondary}\n\n enum MarketLayout {ZeroMarkets, OneMarket, TwoMarkets}\n\n struct ActionArgs {\n ActionType actionType;\n uint256 accountId;\n Types.AssetAmount amount;\n uint256 primaryMarketId;\n uint256 secondaryMarketId;\n address otherAddress;\n uint256 otherAccountId;\n bytes data;\n }\n\n struct DepositArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 market;\n address from;\n }\n\n struct WithdrawArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 market;\n address to;\n }\n\n struct TransferArgs {\n Types.AssetAmount amount;\n Account.Info accountOne;\n Account.Info accountTwo;\n uint256 market;\n }\n\n struct BuyArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 makerMarket;\n uint256 takerMarket;\n address exchangeWrapper;\n bytes orderData;\n }\n\n struct SellArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 takerMarket;\n uint256 makerMarket;\n address exchangeWrapper;\n bytes orderData;\n }\n\n struct TradeArgs {\n Types.AssetAmount amount;\n Account.Info takerAccount;\n Account.Info makerAccount;\n uint256 inputMarket;\n uint256 outputMarket;\n address autoTrader;\n bytes tradeData;\n }\n\n struct LiquidateArgs {\n Types.AssetAmount amount;\n Account.Info solidAccount;\n Account.Info liquidAccount;\n uint256 owedMarket;\n uint256 heldMarket;\n }\n\n struct VaporizeArgs {\n Types.AssetAmount amount;\n Account.Info solidAccount;\n Account.Info vaporAccount;\n uint256 owedMarket;\n uint256 heldMarket;\n }\n\n struct CallArgs {\n Account.Info account;\n address callee;\n bytes data;\n }\n}\n\n// Part: ICallee\n\n/**\n * @title ICallee\n * @author dYdX\n *\n * Interface that Callees for Solo must implement in order to ingest data.\n */\ninterface ICallee {\n // ============ Public Functions ============\n\n /**\n * Allows users to send this contract arbitrary data.\n *\n * @param sender The msg.sender to Solo\n * @param accountInfo The account from which the data is being sent\n * @param data Arbitrary data given by the sender\n */\n function callFunction(\n address sender,\n Account.Info memory accountInfo,\n bytes memory data\n ) external;\n}\n\n// Part: ILendingPool\n\ninterface ILendingPool {\n function addressesProvider() external view returns (address);\n\n function deposit(\n address _reserve,\n uint256 _amount,\n uint16 _referralCode\n ) external payable;\n\n function redeemUnderlying(\n address _reserve,\n address _user,\n uint256 _amount\n ) external;\n\n function borrow(\n address _reserve,\n uint256 _amount,\n uint256 _interestRateMode,\n uint16 _referralCode\n ) external;\n\n function repay(\n address _reserve,\n uint256 _amount,\n address _onBehalfOf\n ) external payable;\n\n function swapBorrowRateMode(address _reserve) external;\n\n function rebalanceFixedBorrowRate(address _reserve, address _user) external;\n\n function setUserUseReserveAsCollateral(address _reserve, bool _useAsCollateral) external;\n\n function liquidationCall(\n address _collateral,\n address _reserve,\n address _user,\n uint256 _purchaseAmount,\n bool _receiveAToken\n ) external payable;\n\n function flashLoan(\n address _receiver,\n address _reserve,\n uint256 _amount,\n bytes calldata _params\n ) external;\n\n function getReserveConfigurationData(address _reserve)\n external\n view\n returns (\n uint256 ltv,\n uint256 liquidationThreshold,\n uint256 liquidationDiscount,\n address interestRateStrategyAddress,\n bool usageAsCollateralEnabled,\n bool borrowingEnabled,\n bool fixedBorrowRateEnabled,\n bool isActive\n );\n\n function getReserveData(address _reserve)\n external\n view\n returns (\n uint256 totalLiquidity,\n uint256 availableLiquidity,\n uint256 totalBorrowsFixed,\n uint256 totalBorrowsVariable,\n uint256 liquidityRate,\n uint256 variableBorrowRate,\n uint256 fixedBorrowRate,\n uint256 averageFixedBorrowRate,\n uint256 utilizationRate,\n uint256 liquidityIndex,\n uint256 variableBorrowIndex,\n address aTokenAddress,\n uint40 lastUpdateTimestamp\n );\n\n function getUserAccountData(address _user)\n external\n view\n returns (\n uint256 totalLiquidityETH,\n uint256 totalCollateralETH,\n uint256 totalBorrowsETH,\n uint256 availableBorrowsETH,\n uint256 currentLiquidationThreshold,\n uint256 ltv,\n uint256 healthFactor\n );\n\n function getUserReserveData(address _reserve, address _user)\n external\n view\n returns (\n uint256 currentATokenBalance,\n uint256 currentUnderlyingBalance,\n uint256 currentBorrowBalance,\n uint256 principalBorrowBalance,\n uint256 borrowRateMode,\n uint256 borrowRate,\n uint256 liquidityRate,\n uint256 originationFee,\n uint256 variableBorrowIndex,\n uint256 lastUpdateTimestamp,\n bool usageAsCollateralEnabled\n );\n\n function getReserves() external view;\n}\n\n// Part: ILendingPoolAddressesProvider\n\n/**\n @title ILendingPoolAddressesProvider interface\n @notice provides the interface to fetch the LendingPoolCore address\n */\n\ninterface ILendingPoolAddressesProvider {\n function getLendingPoolCore() external view returns (address payable);\n\n function getLendingPool() external view returns (address);\n}\n\n// Part: ISoloMargin\n\ninterface ISoloMargin {\n struct OperatorArg {\n address operator1;\n bool trusted;\n }\n\n function ownerSetSpreadPremium(uint256 marketId, Decimal.D256 memory spreadPremium) external;\n\n function getIsGlobalOperator(address operator1) external view returns (bool);\n\n function getMarketTokenAddress(uint256 marketId) external view returns (address);\n\n function ownerSetInterestSetter(uint256 marketId, address interestSetter) external;\n\n function getAccountValues(Account.Info memory account) external view returns (Monetary.Value memory, Monetary.Value memory);\n\n function getMarketPriceOracle(uint256 marketId) external view returns (address);\n\n function getMarketInterestSetter(uint256 marketId) external view returns (address);\n\n function getMarketSpreadPremium(uint256 marketId) external view returns (Decimal.D256 memory);\n\n function getNumMarkets() external view returns (uint256);\n\n function ownerWithdrawUnsupportedTokens(address token, address recipient) external returns (uint256);\n\n function ownerSetMinBorrowedValue(Monetary.Value memory minBorrowedValue) external;\n\n function ownerSetLiquidationSpread(Decimal.D256 memory spread) external;\n\n function ownerSetEarningsRate(Decimal.D256 memory earningsRate) external;\n\n function getIsLocalOperator(address owner, address operator1) external view returns (bool);\n\n function getAccountPar(Account.Info memory account, uint256 marketId) external view returns (Types.Par memory);\n\n function ownerSetMarginPremium(uint256 marketId, Decimal.D256 memory marginPremium) external;\n\n function getMarginRatio() external view returns (Decimal.D256 memory);\n\n function getMarketCurrentIndex(uint256 marketId) external view returns (Interest.Index memory);\n\n function getMarketIsClosing(uint256 marketId) external view returns (bool);\n\n function getRiskParams() external view returns (Storage.RiskParams memory);\n\n function getAccountBalances(Account.Info memory account)\n external\n view\n returns (\n address[] memory,\n Types.Par[] memory,\n Types.Wei[] memory\n );\n\n function renounceOwnership() external;\n\n function getMinBorrowedValue() external view returns (Monetary.Value memory);\n\n function setOperators(OperatorArg[] memory args) external;\n\n function getMarketPrice(uint256 marketId) external view returns (address);\n\n function owner() external view returns (address);\n\n function isOwner() external view returns (bool);\n\n function ownerWithdrawExcessTokens(uint256 marketId, address recipient) external returns (uint256);\n\n function ownerAddMarket(\n address token,\n address priceOracle,\n address interestSetter,\n Decimal.D256 memory marginPremium,\n Decimal.D256 memory spreadPremium\n ) external;\n\n function operate(Account.Info[] memory accounts, Actions.ActionArgs[] memory actions) external;\n\n function getMarketWithInfo(uint256 marketId)\n external\n view\n returns (\n Storage.Market memory,\n Interest.Index memory,\n Monetary.Price memory,\n Interest.Rate memory\n );\n\n function ownerSetMarginRatio(Decimal.D256 memory ratio) external;\n\n function getLiquidationSpread() external view returns (Decimal.D256 memory);\n\n function getAccountWei(Account.Info memory account, uint256 marketId) external view returns (Types.Wei memory);\n\n function getMarketTotalPar(uint256 marketId) external view returns (Types.TotalPar memory);\n\n function getLiquidationSpreadForPair(uint256 heldMarketId, uint256 owedMarketId) external view returns (Decimal.D256 memory);\n\n function getNumExcessTokens(uint256 marketId) external view returns (Types.Wei memory);\n\n function getMarketCachedIndex(uint256 marketId) external view returns (Interest.Index memory);\n\n function getAccountStatus(Account.Info memory account) external view returns (uint8);\n\n function getEarningsRate() external view returns (Decimal.D256 memory);\n\n function ownerSetPriceOracle(uint256 marketId, address priceOracle) external;\n\n function getRiskLimits() external view returns (Storage.RiskLimits memory);\n\n function getMarket(uint256 marketId) external view returns (Storage.Market memory);\n\n function ownerSetIsClosing(uint256 marketId, bool isClosing) external;\n\n function ownerSetGlobalOperator(address operator1, bool approved) external;\n\n function transferOwnership(address newOwner) external;\n\n function getAdjustedAccountValues(Account.Info memory account) external view returns (Monetary.Value memory, Monetary.Value memory);\n\n function getMarketMarginPremium(uint256 marketId) external view returns (Decimal.D256 memory);\n\n function getMarketInterestRate(uint256 marketId) external view returns (Interest.Rate memory);\n}\n\n// Part: IUni\n\ninterface IUni{\n function getAmountsOut(\n uint256 amountIn, \n address[] calldata path\n ) external view returns (uint256[] memory amounts);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n}\n\n// Part: InterestRateModel\n\ninterface InterestRateModel {\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves\n ) external view returns (uint256, uint256);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa\n ) external view returns (uint256);\n}\n\n// Part: OpenZeppelin/[email protected]/Address\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 // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly { codehash := extcodehash(account) }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n (bool success, ) = recipient.call{ value: amount }(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain`call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n return _functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n return _functionCallWithValue(target, data, value, errorMessage);\n }\n\n function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {\n require(isContract(target), \"Address: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n\n// Part: OpenZeppelin/[email protected]/IERC20\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\n// Part: OpenZeppelin/[email protected]/Math\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\n// Part: OpenZeppelin/[email protected]/SafeMath\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n\n// Part: Types\n\nlibrary Types {\n enum AssetDenomination {\n Wei, // the amount is denominated in wei\n Par // the amount is denominated in par\n }\n\n enum AssetReference {\n Delta, // the amount is given as a delta from the current value\n Target // the amount is given as an exact number to end up at\n }\n\n struct AssetAmount {\n bool sign; // true if positive\n AssetDenomination denomination;\n AssetReference ref;\n uint256 value;\n }\n\n struct TotalPar {\n uint128 borrow;\n uint128 supply;\n }\n\n struct Par {\n bool sign; // true if positive\n uint128 value;\n }\n\n struct Wei {\n bool sign; // true if positive\n uint256 value;\n }\n}\n\n// Part: CTokenI\n\ninterface CTokenI {\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address minter, uint256 mintAmount, uint256 mintTokens);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemTokens);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(address payer, address borrower, uint256 repayAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(address liquidator, address borrower, uint256 repayAmount, address cTokenCollateral, uint256 seizeTokens);\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when pendingAdmin is changed\n */\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\n\n /**\n * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\n */\n event NewAdmin(address oldAdmin, address newAdmin);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address admin, uint256 reduceAmount, uint256 newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /**\n * @notice Failure event\n */\n event Failure(uint256 error, uint256 info, uint256 detail);\n\n function transfer(address dst, uint256 amount) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external returns (bool);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address owner) external view returns (uint256);\n\n function balanceOfUnderlying(address owner) external returns (uint256);\n\n function getAccountSnapshot(address account)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function borrowRatePerBlock() external view returns (uint256);\n\n function supplyRatePerBlock() external view returns (uint256);\n\n function totalBorrowsCurrent() external returns (uint256);\n\n function borrowBalanceCurrent(address account) external returns (uint256);\n\n function borrowBalanceStored(address account) external view returns (uint256);\n\n function exchangeRateCurrent() external returns (uint256);\n\n function accrualBlockNumber() external view returns (uint256);\n\n function exchangeRateStored() external view returns (uint256);\n\n function getCash() external view returns (uint256);\n\n function accrueInterest() external returns (uint256);\n\n function interestRateModel() external view returns (InterestRateModel);\n\n function totalReserves() external view returns (uint256);\n\n function reserveFactorMantissa() external view returns (uint256);\n\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external returns (uint256);\n\n function totalBorrows() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n}\n\n// Part: DydxFlashloanBase\n\ncontract DydxFlashloanBase {\n using SafeMath for uint256;\n\n\n function _getAccountInfo() internal view returns (Account.Info memory) {\n return Account.Info({owner: address(this), number: 1});\n }\n\n function _getWithdrawAction(uint256 marketId, uint256 amount) internal view returns (Actions.ActionArgs memory) {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Withdraw,\n accountId: 0,\n amount: Types.AssetAmount({\n sign: false,\n denomination: Types.AssetDenomination.Wei,\n ref: Types.AssetReference.Delta,\n value: amount\n }),\n primaryMarketId: marketId,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: \"\"\n });\n }\n\n function _getCallAction(bytes memory data) internal view returns (Actions.ActionArgs memory) {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Call,\n accountId: 0,\n amount: Types.AssetAmount({sign: false, denomination: Types.AssetDenomination.Wei, ref: Types.AssetReference.Delta, value: 0}),\n primaryMarketId: 0,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: data\n });\n }\n\n function _getDepositAction(uint256 marketId, uint256 amount) internal view returns (Actions.ActionArgs memory) {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Deposit,\n accountId: 0,\n amount: Types.AssetAmount({\n sign: true,\n denomination: Types.AssetDenomination.Wei,\n ref: Types.AssetReference.Delta,\n value: amount\n }),\n primaryMarketId: marketId,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: \"\"\n });\n }\n}\n\n// Part: OpenZeppelin/[email protected]/SafeERC20\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require((value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) { // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\n// Part: iearn-finance/[email protected]/VaultAPI\n\ninterface VaultAPI is IERC20 {\n function apiVersion() external view returns (string memory);\n\n function withdraw(uint256 shares, address recipient) external;\n\n function token() external view returns (address);\n\n function strategies(address _strategy) external view returns (StrategyParams memory);\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// Part: CErc20I\n\ninterface CErc20I is CTokenI {\n function mint(uint256 mintAmount) external returns (uint256);\n\n function redeem(uint256 redeemTokens) external returns (uint256);\n\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256);\n\n function borrow(uint256 borrowAmount) external returns (uint256);\n\n function repayBorrow(uint256 repayAmount) external returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n CTokenI cTokenCollateral\n ) external returns (uint256);\n\n function underlying() external view returns (address);\n}\n\n// Part: ComptrollerI\n\ninterface ComptrollerI {\n function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory);\n\n function exitMarket(address cToken) external returns (uint256);\n\n /*** Policy Hooks ***/\n\n function mintAllowed(\n address cToken,\n address minter,\n uint256 mintAmount\n ) external returns (uint256);\n\n function mintVerify(\n address cToken,\n address minter,\n uint256 mintAmount,\n uint256 mintTokens\n ) external;\n\n function redeemAllowed(\n address cToken,\n address redeemer,\n uint256 redeemTokens\n ) external returns (uint256);\n\n function redeemVerify(\n address cToken,\n address redeemer,\n uint256 redeemAmount,\n uint256 redeemTokens\n ) external;\n\n function borrowAllowed(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external returns (uint256);\n\n function borrowVerify(\n address cToken,\n address borrower,\n uint256 borrowAmount\n ) external;\n\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint256 repayAmount\n ) external returns (uint256);\n\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint256 repayAmount,\n uint256 borrowerIndex\n ) external;\n\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint256 repayAmount\n ) external returns (uint256);\n\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint256 repayAmount,\n uint256 seizeTokens\n ) external;\n\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external returns (uint256);\n\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external;\n\n function transferAllowed(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external returns (uint256);\n\n function transferVerify(\n address cToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external;\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint256 repayAmount\n ) external view returns (uint256, uint256);\n\n function getAccountLiquidity(address account)\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /*** Comp claims ****/\n function claimComp(address holder) external;\n\n function claimComp(address holder, CTokenI[] memory cTokens) external;\n\n function markets(address ctoken)\n external\n view\n returns (\n bool,\n uint256,\n bool\n );\n\n function compSpeeds(address ctoken) external view returns (uint256);\n}\n\n// Part: iearn-finance/[email protected]/BaseStrategy\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 */\nabstract contract BaseStrategy {\n using SafeMath for uint256;\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.3.0\";\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 virtual view 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 * @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 virtual view 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(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);\n\n event UpdatedStrategist(address newStrategist);\n\n event UpdatedKeeper(address newKeeper);\n\n event UpdatedRewards(address rewards);\n\n event UpdatedReportDelay(uint256 delay);\n\n event UpdatedProfitFactor(uint256 profitFactor);\n\n event UpdatedDebtThreshold(uint256 debtThreshold);\n\n event EmergencyExitEnabled();\n\n // The maximum number of seconds between harvest calls. See\n // `setMaxReportDelay()` for more details.\n uint256 public maxReportDelay = 86400; // ~ once a day\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 = 100;\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 = 0;\n\n // See note on `setEmergencyExit()`.\n bool public emergencyExit;\n\n // modifiers\n modifier onlyAuthorized() {\n require(msg.sender == strategist || msg.sender == governance(), \"!authorized\");\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(msg.sender == keeper || msg.sender == strategist || msg.sender == governance(), \"!authorized\");\n _;\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 */\n constructor(address _vault) public {\n vault = VaultAPI(_vault);\n want = IERC20(vault.token());\n want.approve(_vault, uint256(-1)); // Give Vault unlimited access (might save gas)\n strategist = msg.sender;\n rewards = msg.sender;\n keeper = msg.sender;\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`. Any distributed rewards will cease flowing\n * to the old address and begin flowing to this address once the change\n * is in effect.\n *\n * This may only be called by the strategist.\n * @param _rewards The address to use for collecting rewards.\n */\n function setRewards(address _rewards) external onlyStrategist {\n require(_rewards != address(0));\n rewards = _rewards;\n emit UpdatedRewards(_rewards);\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 UpdatedReportDelay(_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 * 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 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 virtual view 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 vault.strategies(address(this)).debtRatio > 0 || 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 - _loss`).\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). This function is used during emergency exit instead of\n * `prepareReturn()` to liquidate all of the Strategy's positions back to the Vault.\n *\n * NOTE: The invariant `_amountFreed + _loss <= _amountNeeded` should always be maintained\n */\n function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss);\n\n /**\n * `Harvest()` calls this function after shares are created during\n * `vault.report()`. You can customize this function to any share\n * distribution mechanism you want.\n *\n * See `vault.report()` for further details.\n */\n function distributeRewards() internal virtual {\n // Transfer 100% of newly-minted shares awarded to this contract to the rewards address.\n uint256 balance = vault.balanceOf(address(this));\n if (balance > 0) {\n vault.transfer(rewards, balance);\n }\n }\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 * `callCost` must be priced in terms of `want`.\n *\n * This call and `harvestTrigger()` should never return `true` at the same\n * time.\n * @param callCost The keeper's estimated cast cost to call `tend()`.\n * @return `true` if `tend()` should be called, `false` otherwise.\n */\n function tendTrigger(uint256 callCost) public virtual view returns (bool) {\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 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 * `callCost` must be priced in terms of `want`.\n *\n * This call and `tendTrigger` should never return `true` at the\n * same time.\n *\n * See `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 callCost The keeper's estimated cast cost to call `harvest()`.\n * @return `true` if `harvest()` should be called, `false` otherwise.\n */\n function harvestTrigger(uint256 callCost) public virtual view returns (bool) {\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 trigger if hasn't been called in a while\n if (block.timestamp.sub(params.lastReport) >= maxReportDelay) 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 totalAssets = estimatedTotalAssets();\n // NOTE: use the larger of total assets or debt outstanding to book losses properly\n (debtPayment, loss) = liquidatePosition(totalAssets > debtOutstanding ? totalAssets : debtOutstanding);\n // NOTE: take up any remainder here as profit\n if (debtPayment > debtOutstanding) {\n profit = debtPayment.sub(debtOutstanding);\n debtPayment = debtOutstanding;\n }\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 // Distribute any reward shares earned by the strategy on this report\n distributeRewards();\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 `_amount`\n uint256 amountFreed;\n (amountFreed, _loss) = liquidatePosition(_amountNeeded);\n // Send it directly back (NOTE: Using `msg.sender` saves some gas here)\n want.transfer(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 governance or the Vault.\n * @dev\n * The new Strategy's Vault must be the same as this Strategy's Vault.\n * @param _newStrategy The Strategy to migrate to.\n */\n function migrate(address _newStrategy) external {\n require(msg.sender == address(vault) || msg.sender == governance());\n require(BaseStrategy(_newStrategy).vault() == vault);\n prepareMigration(_newStrategy);\n want.transfer(_newStrategy, want.balanceOf(address(this)));\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 onlyAuthorized {\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 function protectedTokens() internal virtual view 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++) require(_token != _protectedTokens[i], \"!protected\");\n\n IERC20(_token).transfer(governance(), IERC20(_token).balanceOf(address(this)));\n }\n}\n\n// File: Strategy.sol\n\n/********************\n *\n * A lender optimisation strategy for any erc20 asset\n * https://github.com/Grandthrax/yearnV2-generic-lender-strat\n * v0.2.2\n *\n ********************* */\n\ncontract Strategy is BaseStrategy, DydxFlashloanBase, ICallee {\n using SafeERC20 for IERC20;\n using Address for address;\n using SafeMath for uint256;\n\n // @notice emitted when trying to do Flash Loan. flashLoan address is 0x00 when no flash loan used\n event Leverage(uint256 amountRequested, uint256 amountGiven, bool deficit, address flashLoan);\n\n //Flash Loan Providers\n address private constant SOLO = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;\n address private constant AAVE_LENDING = 0x24a42fD28C976A61Df5D00D0599C34c4f90748c8;\n ILendingPoolAddressesProvider public addressesProvider;\n\n // Comptroller address for compound.finance\n ComptrollerI public constant compound = ComptrollerI(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);\n\n //Only three tokens we use\n address public constant comp = address(0xc00e94Cb662C3520282E6f5717214004A7f26888);\n CErc20I public cToken;\n //address public constant DAI = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);\n\n address public constant uniswapRouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);\n address public constant weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n\n //Operating variables\n uint256 public collateralTarget = 0.73 ether; // 73%\n uint256 public blocksToLiquidationDangerZone = 46500; // 7 days = 60*60*24*7/13\n\n uint256 public minWant = 0; //Only lend if we have enough want to be worth it. Can be set to non-zero\n uint256 public minCompToSell = 0.1 ether; //used both as the threshold to sell but also as a trigger for harvest\n\n //To deactivate flash loan provider if needed\n bool public DyDxActive = true;\n bool public AaveActive = false;\n\n uint256 public dyDxMarketId;\n\n constructor(address _vault, address _cToken) public BaseStrategy(_vault) {\n cToken = CErc20I(address(_cToken));\n\n //pre-set approvals\n IERC20(comp).safeApprove(uniswapRouter, uint256(-1));\n want.safeApprove(address(cToken), uint256(-1));\n want.safeApprove(SOLO, uint256(-1));\n\n // You can set these parameters on deployment to whatever you want\n maxReportDelay = 86400; // once per 24 hours\n profitFactor = 100; // multiple before triggering harvest\n\n _setMarketIdFromTokenAddress();\n\n addressesProvider = ILendingPoolAddressesProvider(AAVE_LENDING);\n\n //we do this horrible thing because you can't compare strings in solidity\n require(keccak256(bytes(apiVersion())) == keccak256(bytes(VaultAPI(_vault).apiVersion())), \"WRONG VERSION\");\n }\n\n function name() external override view returns (string memory){\n return \"StrategyGenericLevCompFarm\";\n }\n\n /*\n * Control Functions\n */\n function setDyDx(bool _dydx) external management {\n DyDxActive = _dydx;\n }\n\n function setAave(bool _ave) external management {\n AaveActive = _ave;\n }\n\n function setMinCompToSell(uint256 _minCompToSell) external management {\n minCompToSell = _minCompToSell;\n }\n\n function setMinWant(uint256 _minWant) external management {\n minWant = _minWant;\n }\n\n function updateMarketId() external management {\n _setMarketIdFromTokenAddress();\n }\n\n function setCollateralTarget(uint256 _collateralTarget) external management {\n (, uint256 collateralFactorMantissa, ) = compound.markets(address(cToken));\n require(collateralFactorMantissa > _collateralTarget, \"!dangerous collateral\");\n collateralTarget = _collateralTarget;\n }\n\n /*\n * Base External Facing Functions\n */\n /*\n * An accurate estimate for the total amount of assets (principle + return)\n * that this strategy is currently managing, denominated in terms of want tokens.\n */\n function estimatedTotalAssets() public override view returns (uint256) {\n (uint256 deposits, uint256 borrows) = getCurrentPosition();\n\n uint256 _claimableComp = predictCompAccrued();\n uint256 currentComp = IERC20(comp).balanceOf(address(this));\n\n // Use touch price. it doesnt matter if we are wrong as this is not used for decision making\n uint256 estimatedWant = priceCheck(comp, address(want),_claimableComp.add(currentComp));\n uint256 conservativeWant = estimatedWant.mul(9).div(10); //10% pessimist\n\n return want.balanceOf(address(this)).add(deposits).add(conservativeWant).sub(borrows);\n }\n\n //predicts our profit at next report\n function expectedReturn() public view returns (uint256) {\n uint256 estimateAssets = estimatedTotalAssets();\n\n uint256 debt = vault.strategies(address(this)).totalDebt;\n if (debt > estimateAssets) {\n return 0;\n } else {\n return estimateAssets - debt;\n }\n }\n\n /*\n * Provide a signal to the keeper that `tend()` should be called.\n * (keepers are always reimbursed by yEarn)\n *\n * NOTE: this call and `harvestTrigger` should never return `true` at the same time.\n * tendTrigger should be called with same gasCost as harvestTrigger\n */\n function tendTrigger(uint256 gasCost) public override view returns (bool) {\n if (harvestTrigger(gasCost)) {\n //harvest takes priority\n return false;\n }\n\n if (getblocksUntilLiquidation() <= blocksToLiquidationDangerZone) {\n return true;\n }\n }\n\n /*\n * Provide a signal to the keeper that `harvest()` should be called.\n * gasCost is expected_gas_use * gas_price\n * (keepers are always reimbursed by yEarn)\n *\n * NOTE: this call and `tendTrigger` should never return `true` at the same time.\n */\n function harvestTrigger(uint256 gasCost) public override view returns (bool) {\n \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\n uint256 wantGasCost = priceCheck(weth, address(want), gasCost);\n uint256 compGasCost = priceCheck(weth, comp, gasCost);\n\n // after enough comp has accrued we want the bot to run\n uint256 _claimableComp = predictCompAccrued();\n\n if (_claimableComp > minCompToSell) {\n // check value of COMP in wei\n if ( _claimableComp.add(IERC20(comp).balanceOf(address(this))) > compGasCost.mul(profitFactor)) {\n return true;\n }\n }\n\n\n // Should trigger if hadn't been called in a while\n if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true;\n\n //check if vault wants lots of money back\n // dont return dust\n uint256 outstanding = vault.debtOutstanding();\n if (outstanding > profitFactor.mul(wantGasCost)) return true;\n\n // Check for profits and losses\n uint256 total = estimatedTotalAssets();\n\n uint256 profit = 0;\n if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!\n\n uint256 credit = vault.creditAvailable().add(profit);\n return (profitFactor.mul(wantGasCost) < credit);\n }\n\n //WARNING. manipulatable and simple routing. Only use for safe functions\n function priceCheck(address start, address end, uint256 _amount) public view returns (uint256) {\n if (_amount == 0) {\n return 0;\n }\n address[] memory path;\n if(start == weth){\n path = new address[](2);\n path[0] = weth;\n path[1] = end;\n }else{\n path = new address[](3);\n path[0] = start; \n path[1] = weth; \n path[2] = end;\n }\n \n uint256[] memory amounts = IUni(uniswapRouter).getAmountsOut(_amount, path);\n\n return amounts[amounts.length - 1];\n }\n\n /*****************\n * Public non-base function\n ******************/\n\n //Calculate how many blocks until we are in liquidation based on current interest rates\n //WARNING does not include compounding so the estimate becomes more innacurate the further ahead we look\n //equation. Compound doesn't include compounding for most blocks\n //((deposits*colateralThreshold - borrows) / (borrows*borrowrate - deposits*colateralThreshold*interestrate));\n function getblocksUntilLiquidation() public view returns (uint256) {\n (, uint256 collateralFactorMantissa, ) = compound.markets(address(cToken));\n\n (uint256 deposits, uint256 borrows) = getCurrentPosition();\n\n uint256 borrrowRate = cToken.borrowRatePerBlock();\n\n uint256 supplyRate = cToken.supplyRatePerBlock();\n\n uint256 collateralisedDeposit1 = deposits.mul(collateralFactorMantissa).div(1e18);\n uint256 collateralisedDeposit = collateralisedDeposit1;\n\n uint256 denom1 = borrows.mul(borrrowRate);\n uint256 denom2 = collateralisedDeposit.mul(supplyRate);\n\n if (denom2 >= denom1) {\n return uint256(-1);\n } else {\n uint256 numer = collateralisedDeposit.sub(borrows);\n uint256 denom = denom1 - denom2;\n //minus 1 for this block\n return numer.mul(1e18).div(denom);\n }\n }\n\n // This function makes a prediction on how much comp is accrued\n // It is not 100% accurate as it uses current balances in Compound to predict into the past\n function predictCompAccrued() public view returns (uint256) {\n (uint256 deposits, uint256 borrows) = getCurrentPosition();\n if (deposits == 0) {\n return 0; // should be impossible to have 0 balance and positive comp accrued\n }\n\n //comp speed is amount to borrow or deposit (so half the total distribution for want)\n uint256 distributionPerBlock = compound.compSpeeds(address(cToken));\n\n uint256 totalBorrow = cToken.totalBorrows();\n\n //total supply needs to be echanged to underlying using exchange rate\n uint256 totalSupplyCtoken = cToken.totalSupply();\n uint256 totalSupply = totalSupplyCtoken.mul(cToken.exchangeRateStored()).div(1e18);\n\n uint256 blockShareSupply = 0;\n if(totalSupply > 0){\n blockShareSupply = deposits.mul(distributionPerBlock).div(totalSupply);\n }\n \n uint256 blockShareBorrow = 0;\n if(totalBorrow > 0){\n blockShareBorrow = borrows.mul(distributionPerBlock).div(totalBorrow);\n }\n \n //how much we expect to earn per block\n uint256 blockShare = blockShareSupply.add(blockShareBorrow);\n\n //last time we ran harvest\n uint256 lastReport = vault.strategies(address(this)).lastReport;\n uint256 blocksSinceLast= (block.timestamp.sub(lastReport)).div(13); //roughly 13 seconds per block\n\n return blocksSinceLast.mul(blockShare);\n }\n\n //Returns the current position\n //WARNING - this returns just the balance at last time someone touched the cToken token. Does not accrue interst in between\n //cToken is very active so not normally an issue.\n function getCurrentPosition() public view returns (uint256 deposits, uint256 borrows) {\n (, uint256 ctokenBalance, uint256 borrowBalance, uint256 exchangeRate) = cToken.getAccountSnapshot(address(this));\n borrows = borrowBalance;\n\n deposits = ctokenBalance.mul(exchangeRate).div(1e18);\n }\n\n //statechanging version\n function getLivePosition() public returns (uint256 deposits, uint256 borrows) {\n deposits = cToken.balanceOfUnderlying(address(this));\n\n //we can use non state changing now because we updated state with balanceOfUnderlying call\n borrows = cToken.borrowBalanceStored(address(this));\n }\n\n //Same warning as above\n function netBalanceLent() public view returns (uint256) {\n (uint256 deposits, uint256 borrows) = getCurrentPosition();\n return deposits.sub(borrows);\n }\n\n /***********\n * internal core logic\n *********** */\n /*\n * A core method.\n * Called at beggining of harvest before providing report to owner\n * 1 - claim accrued comp\n * 2 - if enough to be worth it we sell\n * 3 - because we lose money on our loans we need to offset profit from comp.\n */\n function prepareReturn(uint256 _debtOutstanding)\n internal\n override\n returns (\n uint256 _profit,\n uint256 _loss,\n uint256 _debtPayment\n ) {\n _profit = 0;\n _loss = 0; //for clarity. also reduces bytesize\n\n if (cToken.balanceOf(address(this)) == 0) {\n uint256 wantBalance = want.balanceOf(address(this));\n //no position to harvest\n //but we may have some debt to return\n //it is too expensive to free more debt in this method so we do it in adjust position\n _debtPayment = Math.min(wantBalance, _debtOutstanding); \n return (_profit, _loss, _debtPayment);\n }\n (uint256 deposits, uint256 borrows) = getLivePosition();\n\n //claim comp accrued\n _claimComp();\n //sell comp\n _disposeOfComp();\n\n uint256 wantBalance = want.balanceOf(address(this));\n\n uint256 investedBalance = deposits.sub(borrows);\n uint256 balance = investedBalance.add(wantBalance);\n\n uint256 debt = vault.strategies(address(this)).totalDebt;\n\n //Balance - Total Debt is profit\n if (balance > debt) {\n _profit = balance - debt;\n\n if (wantBalance < _profit) {\n //all reserve is profit \n _profit = wantBalance;\n } else if (wantBalance > _profit.add(_debtOutstanding)){\n _debtPayment = _debtOutstanding;\n }else{\n _debtPayment = wantBalance - _profit;\n }\n } else {\n //we will lose money until we claim comp then we will make money\n //this has an unintended side effect of slowly lowering our total debt allowed\n _loss = debt - balance;\n _debtPayment = Math.min(wantBalance, _debtOutstanding);\n }\n }\n\n /*\n * Second core function. Happens after report call.\n *\n * Similar to deposit function from V1 strategy\n */\n\n function adjustPosition(uint256 _debtOutstanding) internal override {\n //emergency exit is dealt with in prepareReturn\n if (emergencyExit) {\n return;\n }\n\n //we are spending all our cash unless we have debt outstanding\n uint256 _wantBal = want.balanceOf(address(this));\n if(_wantBal < _debtOutstanding){\n //this is graceful withdrawal. dont use backup\n //we use more than 1 because withdrawunderlying causes problems with 1 token due to different decimals\n if(cToken.balanceOf(address(this)) > 1){ \n _withdrawSome(_debtOutstanding - _wantBal, false);\n }\n\n return;\n }\n \n (uint256 position, bool deficit) = _calculateDesiredPosition(_wantBal - _debtOutstanding, true);\n \n //if we are below minimun want change it is not worth doing\n //need to be careful in case this pushes to liquidation\n if (position > minWant) {\n //if dydx is not active we just try our best with basic leverage\n if (!DyDxActive) {\n uint i = 0;\n while(position > 0){\n position = position.sub(_noFlashLoan(position, deficit));\n if(i >= 6){\n break;\n }\n i++;\n }\n } else {\n //if there is huge position to improve we want to do normal leverage. it is quicker\n if (position > want.balanceOf(SOLO)) {\n position = position.sub(_noFlashLoan(position, deficit));\n }\n\n //flash loan to position\n if(position > 0){\n doDyDxFlashLoan(deficit, position);\n }\n\n }\n }\n }\n\n /*************\n * Very important function\n * Input: amount we want to withdraw and whether we are happy to pay extra for Aave.\n * cannot be more than we have\n * Returns amount we were able to withdraw. notall if user has some balance left\n *\n * Deleverage position -> redeem our cTokens\n ******************** */\n function _withdrawSome(uint256 _amount, bool _useBackup) internal returns (bool notAll) {\n (uint256 position, bool deficit) = _calculateDesiredPosition(_amount, false);\n\n //If there is no deficit we dont need to adjust position\n if (deficit) {\n //we do a flash loan to give us a big gap. from here on out it is cheaper to use normal deleverage. Use Aave for extremely large loans\n if (DyDxActive) {\n position = position.sub(doDyDxFlashLoan(deficit, position));\n }\n\n // Will decrease number of interactions using aave as backup\n // because of fee we only use in emergency\n if (position > 0 && AaveActive && _useBackup) {\n position = position.sub(doAaveFlashLoan(deficit, position));\n }\n\n uint8 i = 0;\n //position will equal 0 unless we haven't been able to deleverage enough with flash loan\n //if we are not in deficit we dont need to do flash loan\n while (position > 0) {\n position = position.sub(_noFlashLoan(position, true));\n i++;\n\n //A limit set so we don't run out of gas\n if (i >= 5) {\n notAll = true;\n break;\n }\n }\n }\n\n //now withdraw\n //if we want too much we just take max\n\n //This part makes sure our withdrawal does not force us into liquidation\n (uint256 depositBalance, uint256 borrowBalance) = getCurrentPosition();\n\n uint256 AmountNeeded = 0;\n if(collateralTarget > 0){\n AmountNeeded = borrowBalance.mul(1e18).div(collateralTarget);\n }\n uint256 redeemable = depositBalance.sub(AmountNeeded);\n\n if (redeemable < _amount) {\n cToken.redeemUnderlying(redeemable);\n } else {\n cToken.redeemUnderlying(_amount);\n }\n\n //let's sell some comp if we have more than needed\n //flash loan would have sent us comp if we had some accrued so we don't need to call claim comp\n _disposeOfComp();\n }\n\n /***********\n * This is the main logic for calculating how to change our lends and borrows\n * Input: balance. The net amount we are going to deposit/withdraw.\n * Input: dep. Is it a deposit or withdrawal\n * Output: position. The amount we want to change our current borrow position.\n * Output: deficit. True if we are reducing position size\n *\n * For instance deficit =false, position 100 means increase borrowed balance by 100\n ****** */\n function _calculateDesiredPosition(uint256 balance, bool dep) internal returns (uint256 position, bool deficit) {\n //we want to use statechanging for safety\n (uint256 deposits, uint256 borrows) = getLivePosition();\n\n //When we unwind we end up with the difference between borrow and supply\n uint256 unwoundDeposit = deposits.sub(borrows);\n\n //we want to see how close to collateral target we are.\n //So we take our unwound deposits and add or remove the balance we are are adding/removing.\n //This gives us our desired future undwoundDeposit (desired supply)\n\n uint256 desiredSupply = 0;\n if (dep) {\n desiredSupply = unwoundDeposit.add(balance);\n } else { \n if(balance > unwoundDeposit) balance = unwoundDeposit;\n desiredSupply = unwoundDeposit.sub(balance);\n }\n\n //(ds *c)/(1-c)\n uint256 num = desiredSupply.mul(collateralTarget);\n uint256 den = uint256(1e18).sub(collateralTarget);\n\n uint256 desiredBorrow = num.div(den);\n if (desiredBorrow > 1e5) {\n //stop us going right up to the wire\n desiredBorrow = desiredBorrow - 1e5;\n }\n\n //now we see if we want to add or remove balance\n // if the desired borrow is less than our current borrow we are in deficit. so we want to reduce position\n if (desiredBorrow < borrows) {\n deficit = true;\n position = borrows - desiredBorrow; //safemath check done in if statement\n } else {\n //otherwise we want to increase position\n deficit = false;\n position = desiredBorrow - borrows;\n }\n }\n\n /*\n * Liquidate as many assets as possible to `want`, irregardless of slippage,\n * up to `_amount`. Any excess should be re-invested here as well.\n */\n function liquidatePosition(uint256 _amountNeeded) internal override returns (uint256 _amountFreed, uint256 _loss) {\n uint256 _balance = want.balanceOf(address(this));\n uint256 assets = netBalanceLent().add(_balance);\n\n uint256 debtOutstanding = vault.debtOutstanding();\n\n if(debtOutstanding > assets){\n _loss = debtOutstanding - assets;\n }\n\n if (assets < _amountNeeded) {\n\n //if we cant afford to withdraw we take all we can\n //withdraw all we can\n (uint256 deposits, uint256 borrows) = getLivePosition();\n\n //1 token causes rounding error with withdrawUnderlying\n if(cToken.balanceOf(address(this)) > 1){ \n _withdrawSome(deposits.sub(borrows), true);\n }\n\n _amountFreed = Math.min(_amountNeeded, want.balanceOf(address(this)));\n \n } else {\n if (_balance < _amountNeeded) {\n _withdrawSome(_amountNeeded.sub(_balance), true);\n\n //overflow error if we return more than asked for\n _amountFreed = Math.min(_amountNeeded, want.balanceOf(address(this)));\n }else{\n _amountFreed = _amountNeeded;\n }\n }\n }\n\n function _claimComp() internal {\n CTokenI[] memory tokens = new CTokenI[](1);\n tokens[0] = cToken;\n\n compound.claimComp(address(this), tokens);\n }\n\n //sell comp function\n function _disposeOfComp() internal {\n uint256 _comp = IERC20(comp).balanceOf(address(this));\n\n if (_comp > minCompToSell) {\n address[] memory path = new address[](3);\n path[0] = comp;\n path[1] = weth;\n path[2] = address(want);\n\n IUni(uniswapRouter).swapExactTokensForTokens(_comp, uint256(0), path, address(this), now);\n }\n }\n\n //lets leave\n //if we can't deleverage in one go set collateralFactor to 0 and call harvest multiple times until delevered\n function prepareMigration(address _newStrategy) internal override {\n (uint256 deposits, uint256 borrows) = getLivePosition();\n _withdrawSome(deposits.sub(borrows), false);\n\n (, , uint256 borrowBalance, ) = cToken.getAccountSnapshot(address(this));\n\n require(borrowBalance == 0, \"DELEVERAGE_FIRST\");\n\n IERC20 _comp = IERC20(comp);\n uint _compB = _comp.balanceOf(address(this));\n if(_compB > 0){\n _comp.safeTransfer(_newStrategy, _compB);\n }\n }\n\n //Three functions covering normal leverage and deleverage situations\n // max is the max amount we want to increase our borrowed balance\n // returns the amount we actually did\n function _noFlashLoan(uint256 max, bool deficit) internal returns (uint256 amount) {\n //we can use non-state changing because this function is always called after _calculateDesiredPosition\n (uint256 lent, uint256 borrowed) = getCurrentPosition();\n\n //if we have nothing borrowed then we can't deleverage any more\n if (borrowed == 0 && deficit) {\n return 0;\n }\n\n (, uint256 collateralFactorMantissa, ) = compound.markets(address(cToken));\n\n if (deficit) {\n amount = _normalDeleverage(max, lent, borrowed, collateralFactorMantissa);\n } else {\n amount = _normalLeverage(max, lent, borrowed, collateralFactorMantissa);\n }\n\n emit Leverage(max, amount, deficit, address(0));\n }\n\n //maxDeleverage is how much we want to reduce by\n function _normalDeleverage(\n uint256 maxDeleverage,\n uint256 lent,\n uint256 borrowed,\n uint256 collatRatio\n ) internal returns (uint256 deleveragedAmount) {\n uint256 theoreticalLent = 0;\n\n //collat ration should never be 0. if it is something is very wrong... but just incase\n if(collatRatio != 0){\n theoreticalLent = borrowed.mul(1e18).div(collatRatio);\n }\n\n deleveragedAmount = lent.sub(theoreticalLent);\n\n if (deleveragedAmount >= borrowed) {\n deleveragedAmount = borrowed;\n }\n if (deleveragedAmount >= maxDeleverage) {\n deleveragedAmount = maxDeleverage;\n }\n\n cToken.redeemUnderlying(deleveragedAmount);\n\n //our borrow has been increased by no more than maxDeleverage\n cToken.repayBorrow(deleveragedAmount);\n }\n\n //maxDeleverage is how much we want to increase by\n function _normalLeverage(\n uint256 maxLeverage,\n uint256 lent,\n uint256 borrowed,\n uint256 collatRatio\n ) internal returns (uint256 leveragedAmount) {\n uint256 theoreticalBorrow = lent.mul(collatRatio).div(1e18);\n\n leveragedAmount = theoreticalBorrow.sub(borrowed);\n\n if (leveragedAmount >= maxLeverage) {\n leveragedAmount = maxLeverage;\n }\n\n cToken.borrow(leveragedAmount);\n cToken.mint(want.balanceOf(address(this)));\n }\n\n //called by flash loan\n function _loanLogic(\n bool deficit,\n uint256 amount,\n uint256 repayAmount\n ) internal {\n uint256 bal = want.balanceOf(address(this));\n require(bal >= amount, \"FLASH_FAILED\"); // to stop malicious calls\n\n //if in deficit we repay amount and then withdraw\n if (deficit) {\n cToken.repayBorrow(amount);\n\n //if we are withdrawing we take more to cover fee\n cToken.redeemUnderlying(repayAmount);\n } else {\n //check if this failed incase we borrow into liquidation\n require(cToken.mint(bal) == 0, \"mint error\");\n //borrow more to cover fee\n // fee is so low for dydx that it does not effect our liquidation risk.\n //DONT USE FOR AAVE\n cToken.borrow(repayAmount);\n }\n }\n\n function protectedTokens() internal override view returns (address[] memory) {\n\n //want is protected automatically\n address[] memory protected = new address[](2);\n protected[0] = comp;\n protected[1] = address(cToken);\n return protected;\n }\n\n /******************\n * Flash loan stuff\n ****************/\n\n // Flash loan DXDY\n // amount desired is how much we are willing for position to change\n function doDyDxFlashLoan(bool deficit, uint256 amountDesired) internal returns (uint256) {\n uint256 amount = amountDesired;\n ISoloMargin solo = ISoloMargin(SOLO);\n \n // Not enough want in DyDx. So we take all we can\n uint256 amountInSolo = want.balanceOf(SOLO);\n\n if (amountInSolo < amount) {\n amount = amountInSolo;\n }\n\n uint256 repayAmount = amount.add(2); // we need to overcollateralise on way back\n\n bytes memory data = abi.encode(deficit, amount, repayAmount);\n\n // 1. Withdraw $\n // 2. Call callFunction(...)\n // 3. Deposit back $\n Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);\n\n operations[0] = _getWithdrawAction(dyDxMarketId, amount);\n operations[1] = _getCallAction(\n // Encode custom data for callFunction\n data\n );\n operations[2] = _getDepositAction(dyDxMarketId, repayAmount);\n\n Account.Info[] memory accountInfos = new Account.Info[](1);\n accountInfos[0] = _getAccountInfo();\n\n solo.operate(accountInfos, operations);\n\n emit Leverage(amountDesired, amount, deficit, SOLO);\n\n return amount;\n }\n\n //returns our current collateralisation ratio. Should be compared with collateralTarget\n function storedCollateralisation() public view returns (uint256 collat) {\n (uint256 lend, uint256 borrow) = getCurrentPosition();\n if (lend == 0) {\n return 0;\n }\n collat = uint256(1e18).mul(borrow).div(lend);\n }\n\n //DyDx calls this function after doing flash loan\n function callFunction(\n address sender,\n Account.Info memory account,\n bytes memory data\n ) public override {\n (bool deficit, uint256 amount, uint256 repayAmount) = abi.decode(data, (bool, uint256, uint256));\n require(msg.sender == SOLO, \"NOT_SOLO\");\n\n _loanLogic(deficit, amount, repayAmount);\n \n }\n\n bool internal awaitingFlash = false;\n\n function doAaveFlashLoan(bool deficit, uint256 _flashBackUpAmount) internal returns (uint256 amount) {\n //we do not want to do aave flash loans for leveraging up. Fee could put us into liquidation\n if (!deficit) {\n return _flashBackUpAmount;\n }\n\n ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());\n\n uint256 availableLiquidity = want.balanceOf(address(0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3));\n\n if (availableLiquidity < _flashBackUpAmount) {\n amount = availableLiquidity;\n } else {\n amount = _flashBackUpAmount;\n }\n\n bytes memory data = abi.encode(deficit, amount);\n\n //anyone can call aave flash loan to us. (for some reason. grrr)\n awaitingFlash = true;\n\n lendingPool.flashLoan(address(this), address(want), amount, data);\n\n awaitingFlash = false;\n\n emit Leverage(_flashBackUpAmount, amount, deficit, AAVE_LENDING);\n }\n\n //Aave calls this function after doing flash loan\n function executeOperation(\n address _reserve,\n uint256 _amount,\n uint256 _fee,\n bytes calldata _params\n ) external {\n (bool deficit, uint256 amount) = abi.decode(_params, (bool, uint256));\n require(msg.sender == addressesProvider.getLendingPool(), \"NOT_AAVE\");\n require(awaitingFlash, \"Malicious\");\n\n _loanLogic(deficit, amount, amount.add(_fee));\n\n // return the flash loan plus Aave's flash loan fee back to the lending pool\n uint256 totalDebt = _amount.add(_fee);\n\n address core = addressesProvider.getLendingPoolCore();\n IERC20(_reserve).safeTransfer(core, totalDebt);\n }\n\n // -- Internal Helper functions -- //\n\n function _setMarketIdFromTokenAddress() internal {\n ISoloMargin solo = ISoloMargin(SOLO);\n\n uint256 numMarkets = solo.getNumMarkets();\n\n address curToken;\n for (uint256 i = 0; i < numMarkets; i++) {\n curToken = solo.getMarketTokenAddress(i);\n\n if (curToken == address(want)) {\n dyDxMarketId = i;\n return;\n }\n }\n\n revert(\"No marketId found for provided token\");\n }\n\n modifier management(){\n require(msg.sender == governance() || msg.sender == strategist, \"!management\");\n _;\n }\n}\n", "contract_name": "Strategy", "compiler_version": "0.6.12+commit.27d51765", "optimizer_enabled": true, "optimizer_runs": 200, "license_identifier": "GPL-3.0", "bytecode_len": 51966}